From a7eea562fb42d52fe81a4e3631f924c91b663fc4 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 6 Sep 2019 12:55:43 -0700 Subject: [PATCH 001/109] Fix test bug where launcher throws NPE because it isnt loaded yet. Bug: 140635319 Change-Id: Iea90c6816c670d58acf79114fc725602ddc9d0b1 --- tests/src/com/android/launcher3/compat/PromiseIconUiTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java index 7ef946d4c4..efbd9c99c3 100644 --- a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java +++ b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java @@ -48,6 +48,7 @@ public class PromiseIconUiTest extends AbstractLauncherUiTest { public void setUp() throws Exception { super.setUp(); mDevice.pressHome(); + waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null); waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL); mSessionId = -1; } From eacaf8aee60b0af3dc43ee4761f8081c0f087bd5 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Tue, 17 Sep 2019 11:31:11 -0700 Subject: [PATCH 002/109] Enable touches on hotseat area Test: Manual Bug:130294785 Change-Id: Ib3ace6633aae1ad2acc71520afd7bfdc96ffb285 --- src/com/android/launcher3/Hotseat.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 00acdcd2f5..03ee707afa 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -105,8 +105,7 @@ public class Hotseat extends CellLayout implements LogContainerProvider, Insetta @Override public boolean onTouchEvent(MotionEvent event) { - // Don't let if follow through to workspace - return true; + return event.getY() > getCellHeight(); } @Override From 0e1b17f8c49c8bb149b3779e30b3cca17e2b8659 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 19 Sep 2019 09:25:17 -0700 Subject: [PATCH 003/109] [DO NOT MERGE] Fixed a bug where restored promise icons stay promise icons. Test: 1 Turn off WiFi 2 Install app. (Promise icon gets added to home screen). 3 Backup launcher. 4 Restore launcher. 5 Turn on WiFi 6 Note promise icon gets updated with as installation progresses. Will submit to future/master later. Bug: 140212732 Change-Id: I63cedc6c16f5028297fb1a0852ffbd4473319ae9 --- src/com/android/launcher3/WorkspaceItemInfo.java | 2 +- src/com/android/launcher3/model/PackageUpdatedTask.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/WorkspaceItemInfo.java b/src/com/android/launcher3/WorkspaceItemInfo.java index 050a8bef75..9451aae98a 100644 --- a/src/com/android/launcher3/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/WorkspaceItemInfo.java @@ -212,7 +212,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { public ComponentName getTargetComponent() { ComponentName cn = super.getTargetComponent(); if (cn == null && (itemType == Favorites.ITEM_TYPE_SHORTCUT - || hasStatusFlag(FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON))) { + || hasStatusFlag(FLAG_SUPPORTS_WEB_UI|FLAG_AUTOINSTALL_ICON|FLAG_RESTORED_ICON))) { // Legacy shortcuts and promise icons with web UI may not have a componentName but just // a packageName. In that case create a dummy componentName instead of adding additional // check everywhere. diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 4428c8e6df..2d1e94ff87 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -57,6 +57,7 @@ import java.util.HashSet; import java.util.List; import static com.android.launcher3.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; +import static com.android.launcher3.WorkspaceItemInfo.FLAG_RESTORED_ICON; /** * Handles updates due to changes in package manager (app installed/updated/removed) @@ -234,7 +235,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { isTargetValid = LauncherAppsCompat.getInstance(context) .isActivityEnabledForProfile(cn, mUser); } - if (si.hasStatusFlag(FLAG_AUTOINSTALL_ICON)) { + if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) { if (updateWorkspaceItemIntent(context, si, packageName)) { infoUpdated = true; } else if (si.hasPromiseIconUi()) { From 9f6cde1443a8824c065f1ef44cfa25d305cef709 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 18 Sep 2019 19:32:03 -0700 Subject: [PATCH 004/109] Adding tracing for a lab-only flake. Bug: 141275518 Change-Id: I95544a55ef13002f696a82e52d54ffb6251d0e39 --- .../src/com/android/quickstep/views/TaskMenuView.java | 11 +++++++++++ .../src/com/android/quickstep/views/TaskView.java | 4 ++++ src/com/android/launcher3/testing/TestProtocol.java | 1 + 3 files changed, 16 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java index c1f6b82ec2..742d6a24ce 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java @@ -26,6 +26,7 @@ import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -40,6 +41,7 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.TaskOverlayFactory; @@ -159,6 +161,9 @@ public class TaskMenuView extends AbstractFloatingView { } public static TaskMenuView showForTask(TaskView taskView) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "showForTask"); + } BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext()); final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate( R.layout.task_menu, activity.getDragLayer(), false); @@ -166,9 +171,15 @@ public class TaskMenuView extends AbstractFloatingView { } private boolean populateAndShowForTask(TaskView taskView) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "populateAndShowForTask1"); + } if (isAttachedToWindow()) { return false; } + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "populateAndShowForTask2"); + } mActivity.getDragLayer().addView(this); mTaskView = taskView; addMenuOptions(mTaskView); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index bfb961320d..3eed2812a1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -53,6 +53,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.testing.TestProtocol; 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; @@ -390,6 +391,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mIconView.setDrawable(icon); mIconView.setOnClickListener(v -> showTaskMenu(Touch.TAP)); mIconView.setOnLongClickListener(v -> { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "setOnLongClickListener"); + } requestDisallowInterceptTouchEvent(true); return showTaskMenu(Touch.LONGPRESS); }); diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 232a764e01..19c557c9ff 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -86,4 +86,5 @@ public final class TestProtocol { public static final String APP_NOT_DISABLED = "b/139891609"; public static final String ALL_APPS_UPON_RECENTS = "b/139941530"; public static final String STABLE_STATE_MISMATCH = "b/140311911"; + public static final String WELLBEING_NO_TASK_MENU = "b/141275518"; } From ddd0ff44ba0424427e68016dc676ba006d4f70b0 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Tue, 17 Sep 2019 23:34:50 -0700 Subject: [PATCH 005/109] Exclude shortcuts in popup from IconCache. We want to load from/save icons to icon cache for pinned shortcuts only to reduce memory footprint. Bug: 140242324 Change-Id: I25c7d59e29c6e27752b36c2c3c226849d4e177af --- .../android/launcher3/icons/cache/BaseIconCache.java | 12 ++---------- .../android/launcher3/icons/cache/CachingLogic.java | 7 +++++++ .../android/launcher3/icons/ComponentWithLabel.java | 9 ++++++++- src/com/android/launcher3/icons/IconCache.java | 4 ++-- .../launcher3/icons/ShortcutCachingLogic.java | 5 +++++ src/com/android/launcher3/model/LoaderTask.java | 4 ++-- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java index c100f05963..a886c0aa09 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java @@ -273,7 +273,7 @@ public abstract class BaseIconCache { if (entry.icon == null) return; entry.title = cachingLogic.getLabel(object); entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user); - mCache.put(key, entry); + if (cachingLogic.addToMemCache()) mCache.put(key, entry); ContentValues values = newContentValues(entry, entry.title.toString(), componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList)); @@ -312,20 +312,12 @@ public abstract class BaseIconCache { @NonNull ComponentName componentName, @NonNull UserHandle user, @NonNull Supplier infoProvider, @NonNull CachingLogic cachingLogic, boolean usePackageIcon, boolean useLowResIcon) { - return cacheLocked(componentName, user, infoProvider, cachingLogic, usePackageIcon, - useLowResIcon, true); - } - - protected CacheEntry cacheLocked( - @NonNull ComponentName componentName, @NonNull UserHandle user, - @NonNull Supplier infoProvider, @NonNull CachingLogic cachingLogic, - boolean usePackageIcon, boolean useLowResIcon, boolean addToMemCache) { assertWorkerThread(); ComponentKey cacheKey = new ComponentKey(componentName, user); CacheEntry entry = mCache.get(cacheKey); if (entry == null || (entry.isLowRes() && !useLowResIcon)) { entry = new CacheEntry(); - if (addToMemCache) { + if (cachingLogic.addToMemCache()) { mCache.put(cacheKey, entry); } diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index 16bc7ae834..3aa783a14c 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -49,4 +49,11 @@ public interface CachingLogic { default long getLastUpdatedTime(T object, PackageInfo info) { return info.lastUpdateTime; } + + /** + * Returns true the object should be added to mem cache; otherwise returns false. + */ + default boolean addToMemCache() { + return true; + } } diff --git a/src/com/android/launcher3/icons/ComponentWithLabel.java b/src/com/android/launcher3/icons/ComponentWithLabel.java index 46b5002655..832956d7ed 100644 --- a/src/com/android/launcher3/icons/ComponentWithLabel.java +++ b/src/com/android/launcher3/icons/ComponentWithLabel.java @@ -34,9 +34,11 @@ public interface ComponentWithLabel { class ComponentCachingLogic implements CachingLogic { private final PackageManager mPackageManager; + private final boolean mAddToMemCache; - public ComponentCachingLogic(Context context) { + public ComponentCachingLogic(Context context, boolean addToMemCache) { mPackageManager = context.getPackageManager(); + mAddToMemCache = addToMemCache; } @Override @@ -60,5 +62,10 @@ public interface ComponentWithLabel { // Do not load icon. target.icon = BitmapInfo.LOW_RES_ICON; } + + @Override + public boolean addToMemCache() { + return mAddToMemCache; + } } } diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 50b5222d3e..11c7f20537 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -77,7 +77,7 @@ public class IconCache extends BaseIconCache { public IconCache(Context context, InvariantDeviceProfile inv) { super(context, LauncherFiles.APP_ICONS_DB, MODEL_EXECUTOR.getLooper(), inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); - mComponentWithLabelCachingLogic = new ComponentCachingLogic(context); + mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false); mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); mShortcutCachingLogic = new ShortcutCachingLogic(); mLauncherApps = LauncherAppsCompat.getInstance(mContext); @@ -206,7 +206,7 @@ public class IconCache extends BaseIconCache { public synchronized String getTitleNoCache(ComponentWithLabel info) { CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), () -> info, mComponentWithLabelCachingLogic, false /* usePackageIcon */, - true /* useLowResIcon */, false /* addToMemCache */); + true /* useLowResIcon */); return Utilities.trim(entry.title); } diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java index ee79b249ce..5d696fd6f3 100644 --- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java +++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java @@ -64,4 +64,9 @@ public class ShortcutCachingLogic implements CachingLogic { if (shortcutInfo == null) return info.lastUpdateTime; return Math.max(shortcutInfo.getLastChangedTimestamp(), info.lastUpdateTime); } + + @Override + public boolean addToMemCache() { + return false; + } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index ea53dbdde7..583ebee0b1 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -242,8 +242,8 @@ public class LoaderTask implements Runnable { verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 4.3: save widgets in icon cache"); - updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic(mApp.getContext()), - mApp.getModel()::onWidgetLabelsUpdated); + updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic( + mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 5: Finish icon cache update"); From eb71cef62993e4f9da4b7711c1a594da76cbc4c7 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 20 Sep 2019 09:51:18 -0700 Subject: [PATCH 006/109] Playing wallpaper animation if Launcher is destroyed Bug: 140539007 Change-Id: I6573eafda353f4f399768613ef068de86c8f37f4 --- .../QuickstepAppTransitionManagerImpl.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java index 991408c649..f05fc766d5 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -57,6 +57,9 @@ import android.os.Looper; import android.util.Pair; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.anim.Interpolators; @@ -80,9 +83,6 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.WindowManagerWrapper; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - /** * {@link LauncherAppTransitionManager} with Quickstep-specific app transitions for launching from * home and/or all-apps. @@ -766,6 +766,13 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans @Override public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, LauncherAnimationRunner.AnimationResult result) { + if (mLauncher.isDestroyed()) { + AnimatorSet anim = new AnimatorSet(); + anim.play(getClosingWindowAnimators(targetCompats)); + result.setAnimation(anim, mLauncher.getApplicationContext()); + return; + } + if (!mLauncher.hasBeenResumed()) { // If launcher is not resumed, wait until new async-frame after resume mLauncher.addOnResumeCallback(() -> From 3d56046ff8bed9923956223b41772eb48525b425 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 20 Sep 2019 09:37:11 -0700 Subject: [PATCH 007/109] Fixing some tests for 2-button mode Bug: 141315387 Change-Id: I66db3e790f5fbe6bc30999ed599cce03874509be --- .../quickstep/FallbackRecentsTest.java | 5 +-- .../allapps/AllAppsContainerView.java | 30 ++++---------- .../compat/AccessibilityManagerCompat.java | 23 +---------- .../testing/TestInformationHandler.java | 18 ++++++++- .../launcher3/testing/TestProtocol.java | 4 +- .../com/android/launcher3/tapl/AllApps.java | 39 ++++++++++++------- .../android/launcher3/tapl/Background.java | 7 +++- .../tapl/LauncherInstrumentation.java | 9 ----- .../android/launcher3/tapl/TestHelpers.java | 11 ++++-- 9 files changed, 66 insertions(+), 80 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index a15fc3e287..de762838af 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -30,7 +30,6 @@ import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification; import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand; -import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -90,7 +89,6 @@ public class FallbackRecentsTest { public final SimpleActivityRule mActivityMonitor = new SimpleActivityRule(RecentsActivity.class); - public FallbackRecentsTest() throws RemoteException { Instrumentation instrumentation = getInstrumentation(); Context context = instrumentation.getContext(); @@ -161,8 +159,7 @@ public class FallbackRecentsTest { return mLauncher.getBackground().switchToOverview(); } - // TODO: Enable all modes after b/141184247 is fixed - @NavigationModeSwitch(mode = ZERO_BUTTON) + @NavigationModeSwitch @Test public void testOverview() throws Exception { startAppFast(getAppPackageName()); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index d240a7256e..13b7b542f6 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -21,7 +21,6 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; -import android.os.Bundle; import android.os.Process; import android.text.Selection; import android.text.SpannableStringBuilder; @@ -33,6 +32,13 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.android.launcher3.AppInfo; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; @@ -45,9 +51,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.keyboard.FocusedItemDecorator; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ItemInfoMatcher; @@ -58,13 +62,6 @@ import com.android.launcher3.views.BottomUserEducationView; import com.android.launcher3.views.RecyclerViewFastScroller; import com.android.launcher3.views.SpringRelativeLayout; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.dynamicanimation.animation.DynamicAnimation; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - /** * The all apps view container. */ @@ -612,17 +609,4 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo && verticalFadingEdge); } } - - @Override - public boolean performAccessibilityAction(int action, Bundle arguments) { - if (AccessibilityManagerCompat.processTestRequest( - mLauncher, TestProtocol.GET_SCROLL_MESSAGE, action, arguments, - response -> - response.putInt(TestProtocol.SCROLL_Y_FIELD, - getActiveRecyclerView().getCurrentScrollY()))) { - return true; - } - - return super.performAccessibilityAction(action, arguments); - } } diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java index 81c95cbdd4..d47a40e519 100644 --- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java +++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java @@ -21,12 +21,9 @@ import android.os.Bundle; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; -import android.view.accessibility.AccessibilityNodeInfo; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.Utilities; - -import java.util.function.Consumer; +import com.android.launcher3.testing.TestProtocol; public class AccessibilityManagerCompat { @@ -103,24 +100,6 @@ public class AccessibilityManagerCompat { return accessibilityManager; } - public static boolean processTestRequest(Context context, String eventTag, int action, - Bundle request, Consumer responseFiller) { - final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context); - if (accessibilityManager == null) return false; - - // The test sends a request via a ACTION_SET_TEXT. - if (action == AccessibilityNodeInfo.ACTION_SET_TEXT && - eventTag.equals(request.getCharSequence( - AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE))) { - final Bundle response = new Bundle(); - responseFiller.accept(response); - AccessibilityManagerCompat.sendEventToTest( - accessibilityManager, eventTag + TestProtocol.RESPONSE_MESSAGE_POSTFIX, response); - return true; - } - return false; - } - public static int getRecommendedTimeoutMillis(Context context, int originalTimeout, int flags) { if (Utilities.ATLEAST_Q) { return getManager(context).getRecommendedTimeoutMillis(originalTimeout, flags); diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 0d1d1a6709..f5f61cd4ca 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -15,9 +15,10 @@ */ package com.android.launcher3.testing; -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static android.graphics.Bitmap.Config.ARGB_8888; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; @@ -120,6 +121,21 @@ public class TestInformationHandler implements ResourceBasedOverride { break; } + case TestProtocol.REQUEST_APPS_LIST_SCROLL_Y: { + try { + final int deferUpdatesFlags = MAIN_EXECUTOR.submit(() -> + mLauncher.getAppsView().getActiveRecyclerView().getCurrentScrollY()) + .get(); + response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, + deferUpdatesFlags); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + break; + } + case TestProtocol.REQUEST_TOTAL_PSS_KB: { Debug.MemoryInfo mem = new Debug.MemoryInfo(); Debug.getMemoryInfo(mem); diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 19c557c9ff..8f7aa17100 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -20,13 +20,10 @@ package com.android.launcher3.testing; * Protocol for custom accessibility events for communication with UI Automation tests. */ public final class TestProtocol { - public static final String GET_SCROLL_MESSAGE = "TAPL_GET_SCROLL"; - public static final String SCROLL_Y_FIELD = "scrollY"; public static final String STATE_FIELD = "state"; public static final String SWITCHED_TO_STATE_MESSAGE = "TAPL_SWITCHED_TO_STATE"; public static final String SCROLL_FINISHED_MESSAGE = "TAPL_SCROLL_FINISHED"; public static final String PAUSE_DETECTED_MESSAGE = "TAPL_PAUSE_DETECTED"; - public static final String RESPONSE_MESSAGE_POSTFIX = "_RESPONSE"; public static final int NORMAL_STATE_ORDINAL = 0; public static final int SPRING_LOADED_STATE_ORDINAL = 1; public static final int OVERVIEW_STATE_ORDINAL = 2; @@ -71,6 +68,7 @@ public final class TestProtocol { public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list"; public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list"; public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags"; + public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y"; 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_TOTAL_PSS_KB = "total_pss"; diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index f070280ea2..0359ff7e92 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -53,8 +53,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { return LauncherInstrumentation.ContainerType.ALL_APPS; } - private boolean hasClickableIcon( - UiObject2 allAppsContainer, UiObject2 appListRecycler, BySelector appIconSelector) { + private boolean hasClickableIcon(UiObject2 allAppsContainer, UiObject2 appListRecycler, + BySelector appIconSelector, int bottomOffset) { final UiObject2 icon = appListRecycler.findObject(appIconSelector); if (icon == null) { LauncherInstrumentation.log("hasClickableIcon: icon not visible"); @@ -66,6 +66,10 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { LauncherInstrumentation.log("hasClickableIcon: icon center is under search box"); return false; } + if (iconBounds.bottom > bottomOffset) { + LauncherInstrumentation.log("hasClickableIcon: icon center bellow bottom offset"); + return false; + } LauncherInstrumentation.log("hasClickableIcon: icon is clickable"); return true; } @@ -90,21 +94,26 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view"); + + int bottomGestureMargin = ResourceUtils.getNavbarSize( + ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; + int bottomOffset = mLauncher.getDevice().getDisplayHeight() - bottomGestureMargin; allAppsContainer.setGestureMargins( 0, getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1, 0, - ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, - mLauncher.getResources()) + 1); + bottomGestureMargin); final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher); - if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) { + if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, + bottomOffset)) { scrollBackToBeginning(); int attempts = 0; - int scroll = getScroll(allAppsContainer); + int scroll = getAllAppsScroll(); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) { - while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) { + while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, + bottomOffset)) { mLauncher.scroll(allAppsContainer, Direction.DOWN, 0.8f, null, 50); - final int newScroll = getScroll(allAppsContainer); + final int newScroll = getAllAppsScroll(); if (newScroll == scroll) break; mLauncher.assertTrue( @@ -118,7 +127,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { } mLauncher.assertTrue("Unable to scroll to a clickable icon: " + appName, - hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)); + hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, + bottomOffset)); final UiObject2 appIcon = mLauncher.waitForObjectInContainer(appListRecycler, appIconSelector); @@ -136,9 +146,9 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { int attempts = 0; final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5); - for (int scroll = getScroll(allAppsContainer); + for (int scroll = getAllAppsScroll(); scroll != 0; - scroll = getScroll(allAppsContainer)) { + scroll = getAllAppsScroll()) { mLauncher.assertTrue("Negative scroll position", scroll > 0); mLauncher.assertTrue( @@ -154,9 +164,10 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { } } - private int getScroll(UiObject2 allAppsContainer) { - return mLauncher.getAnswerFromLauncher(allAppsContainer, TestProtocol.GET_SCROLL_MESSAGE). - getInt(TestProtocol.SCROLL_Y_FIELD, -1); + private int getAllAppsScroll() { + return mLauncher.getTestInfo( + TestProtocol.REQUEST_APPS_LIST_SCROLL_Y) + .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); } private UiObject2 getSearchBox(UiObject2 allAppsContainer) { diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java index bcce8ef579..9e66740b4b 100644 --- a/tests/tapl/com/android/launcher3/tapl/Background.java +++ b/tests/tapl/com/android/launcher3/tapl/Background.java @@ -104,7 +104,12 @@ public class Background extends LauncherInstrumentation.VisibleContainer { startY = endY = mLauncher.getDevice().getDisplayHeight() / 2; } - mLauncher.swipeToState(startX, startY, endX, endY, 10, expectedState); + if (mLauncher.isFallbackOverview()) { + mLauncher.linearGesture(startX, startY, endX, endY, 10); + new BaseOverview(mLauncher); + } else { + mLauncher.swipeToState(startX, startY, endX, endY, 10, expectedState); + } break; } diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 383c3cef31..1c81b1096f 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -512,15 +512,6 @@ public final class LauncherInstrumentation { } } - Bundle getAnswerFromLauncher(UiObject2 view, String requestTag) { - // Send a fake set-text request to Launcher to initiate a response with requested data. - final String responseTag = requestTag + TestProtocol.RESPONSE_MESSAGE_POSTFIX; - return (Bundle) executeAndWaitForEvent( - () -> view.setText(requestTag), - event -> responseTag.equals(event.getClassName()), - "Launcher didn't respond to request: " + requestTag); - } - /** * Presses nav bar home button. * diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java index a089a527ef..ba0dd73206 100644 --- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java +++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java @@ -77,13 +77,18 @@ public class TestHelpers { return launchers.get(0).activityInfo; } - public static String getOverviewPackageName() { + public static ComponentName getOverviewComponentName() { Resources res = Resources.getSystem(); int id = res.getIdentifier("config_recentsComponentName", "string", "android"); if (id != 0) { - return ComponentName.unflattenFromString(res.getString(id)).getPackageName(); + return ComponentName.unflattenFromString(res.getString(id)); } - return "com.android.systemui"; + return new ComponentName("com.android.systemui", + "com.android.systemui.recents.RecentsActivity"); + } + + public static String getOverviewPackageName() { + return getOverviewComponentName().getPackageName(); } private static String truncateCrash(String text, int maxLines) { From f779e78789d414cb89c3a79f1efd2492600c4526 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 9 Sep 2019 16:46:06 -0700 Subject: [PATCH 008/109] Updating animation start callback Bug: 140626334 Test: Builds Change-Id: I86e8d448188d21f0318ac2ea053a8394a1d0cf1a --- .../util/RecentsAnimationListenerSet.java | 22 +++++++++++++++---- .../launcher3/LauncherAnimationRunner.java | 20 ++++++++++++----- 2 files changed, 32 insertions(+), 10 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 b1999d716c..4299d1a84a 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 @@ -20,6 +20,7 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.graphics.Rect; import android.util.ArraySet; +import androidx.annotation.BinderThread; import androidx.annotation.UiThread; import com.android.launcher3.Utilities; @@ -70,12 +71,14 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { mListeners.remove(listener); } - @Override + // Called only in R+ platform + @BinderThread public final void onAnimationStart(RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] targets, Rect homeContentInsets, - Rect minimizedHomeBounds) { + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, + Rect homeContentInsets, Rect minimizedHomeBounds) { mController = controller; - SwipeAnimationTargetSet targetSet = new SwipeAnimationTargetSet(controller, targets, + SwipeAnimationTargetSet targetSet = new SwipeAnimationTargetSet(controller, appTargets, homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen, mOnFinishListener); @@ -90,6 +93,17 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { } } + // Called only in Q platform + @BinderThread + @Deprecated + public final void onAnimationStart(RecentsAnimationControllerCompat controller, + RemoteAnimationTargetCompat[] appTargets, Rect homeContentInsets, + Rect minimizedHomeBounds) { + onAnimationStart(controller, appTargets, new RemoteAnimationTargetCompat[0], + homeContentInsets, minimizedHomeBounds); + } + + @BinderThread @Override public final void onAnimationCanceled(ThumbnailData thumbnailData) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java index a8e29569b1..a7aab6d080 100644 --- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java +++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java @@ -28,12 +28,12 @@ import android.content.Context; import android.os.Build; import android.os.Handler; -import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; - import androidx.annotation.BinderThread; import androidx.annotation.UiThread; +import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; + @TargetApi(Build.VERSION_CODES.P) public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { @@ -50,13 +50,14 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo mStartAtFrontOfQueue = startAtFrontOfQueue; } + // Called only in R+ platform @BinderThread - @Override - public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) { + public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, Runnable runnable) { Runnable r = () -> { finishExistingAnimation(); mAnimationResult = new AnimationResult(runnable); - onCreateAnimation(targetCompats, mAnimationResult); + onCreateAnimation(appTargets, mAnimationResult); }; if (mStartAtFrontOfQueue) { postAtFrontOfQueueAsynchronously(mHandler, r); @@ -65,6 +66,13 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo } } + // Called only in Q platform + @BinderThread + @Deprecated + public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets, Runnable runnable) { + onAnimationStart(appTargets, new RemoteAnimationTargetCompat[0], runnable); + } + /** * Called on the UI thread when the animation targets are received. The implementation must * call {@link AnimationResult#setAnimation} with the target animation to be run. From 4df06903bc0f136b8054f4b60edda98b1846bc89 Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Fri, 16 Aug 2019 15:01:44 -0700 Subject: [PATCH 009/109] Fill in LauncherTarget fields with values extracted from LauncherLogProto.Target. Test: manual Bug: 137777105 Log result: 1. Swipe to -1: data { elapsed_timestamp_nanos: 1372265229686264 atom { launcher_event { action: SWIPE_LEFT src_state: HOME dst_state: HOME extension { src_target { } } is_swipe_up_enabled: true } } } 2. Swipe out of -1: data { elapsed_timestamp_nanos: 1372368006970305 atom { launcher_event { action: SWIPE_RIGHT src_state: HOME dst_state: HOME extension { src_target { page_id: -1 } } is_swipe_up_enabled: true } } } 3. Launch app from homescreen: data { elapsed_timestamp_nanos: 1372397640628726 atom { launcher_event { action: LAUNCH_APP src_state: HOME dst_state: BACKGROUND extension { src_target { item: APP_ICON grid_x: 2 grid_y: 1 } src_target { } } is_swipe_up_enabled: true } } } 4. Launch app from hotseat: data { elapsed_timestamp_nanos: 1372399813031963 atom { launcher_event { action: LAUNCH_APP src_state: HOME dst_state: BACKGROUND extension { src_target { item: APP_ICON grid_x: 2 } src_target { container: HOTSEAT } } is_swipe_up_enabled: true } } } 5. Launch app from allapps prediction: data { elapsed_timestamp_nanos: 1372403080724736 atom { launcher_event { action: LAUNCH_APP src_state: ALLAPPS dst_state: BACKGROUND extension { src_target { item: APP_ICON } src_target { container: PREDICTION } } is_swipe_up_enabled: true } } } Change-Id: I981401d06577c15948cfee0062b8a6f8a5594345 --- .../logging/StatsLogCompatManager.java | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index bf3cd8afe2..8e5ed1a3ea 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -29,12 +29,16 @@ import android.content.Intent; import android.stats.launcher.nano.Launcher; import android.stats.launcher.nano.LauncherExtension; import android.stats.launcher.nano.LauncherTarget; +import android.util.Log; import android.view.View; import com.android.launcher3.ItemInfo; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogUtils; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.util.ComponentKey; import com.android.systemui.shared.system.StatsLogCompat; import com.google.protobuf.nano.MessageNano; @@ -50,6 +54,8 @@ import com.google.protobuf.nano.MessageNano; public class StatsLogCompatManager extends StatsLogManager { private static final int SUPPORTED_TARGET_DEPTH = 2; + private static final String TAG = "StatsLogCompatManager"; + private static final boolean DEBUG = false; public StatsLogCompatManager(Context context) { } @@ -59,6 +65,9 @@ public class StatsLogCompatManager extends StatsLogManager { ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH]; int srcState = mStateProvider.getCurrentState(); fillInLauncherExtension(v, ext); + if (ext.srcTarget[0] != null) { + ext.srcTarget[0].item = LauncherTarget.APP_ICON; + } StatsLogCompat.write(LAUNCH_APP, srcState, BACKGROUND /* dstState */, MessageNano.toByteArray(ext), true); } @@ -95,28 +104,132 @@ public class StatsLogCompatManager extends StatsLogManager { } public static boolean fillInLauncherExtension(View v, LauncherExtension extension) { + if (DEBUG) { + Log.d(TAG, "fillInLauncherExtension"); + } + StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v); if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) { + if (DEBUG) { + Log.d(TAG, "View or provider is null, or view doesn't have an ItemInfo tag."); + } + return false; } ItemInfo itemInfo = (ItemInfo) v.getTag(); Target child = new Target(); Target parent = new Target(); provider.fillInLogContainerData(v, itemInfo, child, parent); + extension.srcTarget[0] = new LauncherTarget(); + extension.srcTarget[1] = new LauncherTarget(); copy(child, extension.srcTarget[0]); copy(parent, extension.srcTarget[1]); return true; } public static boolean fillInLauncherExtensionWithPageId(LauncherExtension ext, int pageId) { + if (DEBUG) { + Log.d(TAG, "fillInLauncherExtensionWithPageId, pageId = " + pageId); + } + Target target = new Target(); target.pageIndex = pageId; + ext.srcTarget[0] = new LauncherTarget(); copy(target, ext.srcTarget[0]); return true; } private static void copy(Target src, LauncherTarget dst) { - // fill in + if (DEBUG) { + Log.d(TAG, "copy target information from clearcut Target to LauncherTarget."); + } + + // Fill in type + switch (src.type) { + case Target.Type.ITEM: + dst.type = LauncherTarget.ITEM_TYPE; + break; + case Target.Type.CONTROL: + dst.type = LauncherTarget.CONTROL_TYPE; + break; + case Target.Type.CONTAINER: + dst.type = LauncherTarget.CONTAINER_TYPE; + break; + default: + dst.type = LauncherTarget.NONE; + break; + } + + // Fill in item + switch (src.itemType) { + case ItemType.APP_ICON: + dst.item = LauncherTarget.APP_ICON; + break; + case ItemType.SHORTCUT: + dst.item = LauncherTarget.SHORTCUT; + break; + case ItemType.WIDGET: + dst.item = LauncherTarget.WIDGET; + break; + case ItemType.FOLDER_ICON: + dst.item = LauncherTarget.FOLDER_ICON; + break; + case ItemType.DEEPSHORTCUT: + dst.item = LauncherTarget.DEEPSHORTCUT; + break; + case ItemType.SEARCHBOX: + dst.item = LauncherTarget.SEARCHBOX; + break; + case ItemType.EDITTEXT: + dst.item = LauncherTarget.EDITTEXT; + break; + case ItemType.NOTIFICATION: + dst.item = LauncherTarget.NOTIFICATION; + break; + case ItemType.TASK: + dst.item = LauncherTarget.TASK; + break; + default: + dst.item = LauncherTarget.DEFAULT_ITEM; + break; + } + + // Fill in container + switch (src.containerType) { + case ContainerType.HOTSEAT: + dst.container = LauncherTarget.HOTSEAT; + break; + case ContainerType.FOLDER: + dst.container = LauncherTarget.FOLDER; + break; + case ContainerType.PREDICTION: + dst.container = LauncherTarget.PREDICTION; + break; + case ContainerType.SEARCHRESULT: + dst.container = LauncherTarget.SEARCHRESULT; + break; + default: + dst.container = LauncherTarget.DEFAULT_CONTAINER; + break; + } + + // Fill in control + switch (src.controlType) { + case ControlType.UNINSTALL_TARGET: + dst.control = LauncherTarget.UNINSTALL; + break; + case ControlType.REMOVE_TARGET: + dst.control = LauncherTarget.REMOVE; + break; + default: + dst.control = LauncherTarget.DEFAULT_CONTROL; + break; + } + + // Fill in other fields + dst.pageId = src.pageIndex; + dst.gridX = src.gridX; + dst.gridY = src.gridY; } @Override From 9e88a6d8bed7301f646062c93bd4f979daff064c Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 20 Sep 2019 12:54:14 -0700 Subject: [PATCH 010/109] Don't crash when swiping up if there are no TaskViews This can happen in LockTask mode, after enabling Overview. In that case, you are locked to the current task, but are allowed to go to overview but no tasks are shown there. Bug: 139917483 Change-Id: I2180cc5e72c343977ea53cc02907ed8dac0f8bc6 --- .../android/quickstep/LauncherActivityControllerHelper.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index d7afd328db..bbcd3b42db 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -381,6 +381,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe TaskView runningTaskView = recentsView.getRunningTaskView(); if (runningTaskView == null) { runningTaskView = recentsView.getCurrentPageTaskView(); + if (runningTaskView == null) { + // There are no task views in LockTask mode when Overview is enabled. + return; + } } TimeInterpolator oldInterpolator = translateY.getInterpolator(); Rect fallbackInsets = launcher.getDeviceProfile().getInsets(); From 60bf8c117b2388a8f243f20e673c29656548be4a Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 20 Sep 2019 12:54:14 -0700 Subject: [PATCH 011/109] Don't crash when swiping up if there are no TaskViews This can happen in LockTask mode, after enabling Overview. In that case, you are locked to the current task, but are allowed to go to overview but no tasks are shown there. Bug: 139917483 Change-Id: I2180cc5e72c343977ea53cc02907ed8dac0f8bc6 Merged-In: I2180cc5e72c343977ea53cc02907ed8dac0f8bc6 --- .../android/quickstep/LauncherActivityControllerHelper.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 25cc33df01..36eb8a13bd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -381,6 +381,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe TaskView runningTaskView = recentsView.getRunningTaskView(); if (runningTaskView == null) { runningTaskView = recentsView.getTaskViewAt(recentsView.getCurrentPage()); + if (runningTaskView == null) { + // There are no task views in LockTask mode when Overview is enabled. + return; + } } TimeInterpolator oldInterpolator = translateY.getInterpolator(); Rect fallbackInsets = launcher.getDeviceProfile().getInsets(); From 1b231ecc56288fcb4b9638775fc811652bbe6510 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 10 Sep 2019 15:19:05 -0700 Subject: [PATCH 012/109] Updating launcher interface for recents animation change Bug: 140626334 Change-Id: Ib8e837c157bb99db429b7936fdf111e05170ac25 --- .../GoLauncherAppTransitionManagerImpl.java | 14 ++-- .../AppToOverviewAnimationProvider.java | 16 ++-- .../LauncherAppTransitionManagerImpl.java | 15 ++-- .../AppToOverviewAnimationProvider.java | 13 +-- .../quickstep/OverviewCommandHelper.java | 6 +- .../android/quickstep/RecentsActivity.java | 24 +++--- .../com/android/quickstep/TaskViewUtils.java | 5 +- .../util/RecentsAnimationListenerSet.java | 4 +- .../util/SwipeAnimationTargetSet.java | 10 +-- .../launcher3/LauncherAnimationRunner.java | 8 +- .../launcher3/LauncherInitListener.java | 4 +- .../QuickstepAppTransitionManagerImpl.java | 84 +++++++++++-------- .../launcher3/uioverrides/UiFactory.java | 5 +- .../util/RemoteAnimationProvider.java | 9 +- .../util/RemoteAnimationTargetSet.java | 5 +- .../util/RemoteFadeOutAnimationListener.java | 5 +- 16 files changed, 127 insertions(+), 100 deletions(-) diff --git a/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java b/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java index bcb1f5c3b4..3953fd0279 100644 --- a/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java +++ b/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java @@ -40,7 +40,9 @@ public final class GoLauncherAppTransitionManagerImpl extends QuickstepAppTransi @Override protected void composeRecentsLaunchAnimator(AnimatorSet anim, View v, - RemoteAnimationTargetCompat[] targets, boolean launcherClosing) { + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, + boolean launcherClosing) { // Stubbed. Recents launch animation will come from the recents view itself and will not // use remote animations. } @@ -74,21 +76,23 @@ public final class GoLauncherAppTransitionManagerImpl extends QuickstepAppTransi } @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, + public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) { boolean isGoingToRecents = - taskIsATargetWithMode(targetCompats, mLauncher.getTaskId(), MODE_OPENING) + taskIsATargetWithMode(appTargets, mLauncher.getTaskId(), MODE_OPENING) && (mLauncher.getStateManager().getState() == LauncherState.OVERVIEW); if (isGoingToRecents) { IconRecentsView recentsView = mLauncher.getOverviewPanel(); if (!recentsView.isReadyForRemoteAnim()) { recentsView.setOnReadyForRemoteAnimCallback(() -> - postAsyncCallback(mHandler, () -> onCreateAnimation(targetCompats, result)) + postAsyncCallback(mHandler, () -> onCreateAnimation(appTargets, + wallpaperTargets, result)) ); return; } } - super.onCreateAnimation(targetCompats, result); + super.onCreateAnimation(appTargets, wallpaperTargets, result); } } } diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java index 92900f2168..ddf0fff523 100644 --- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -95,11 +95,12 @@ final class AppToOverviewAnimationProvider imple * Create remote window animation from the currently running app to the overview panel. Should * be called after {@link #onActivityReady}. * - * @param targetCompats the target apps + * @param appTargets the target apps * @return animation from app to overview */ @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) { + public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { if (mAnimationReadyListener != null) { mAnimationReadyListener.onWindowAnimationCreated(); } @@ -113,13 +114,13 @@ final class AppToOverviewAnimationProvider imple } RemoteAnimationTargetSet targetSet = - new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING); + new RemoteAnimationTargetSet(appTargets, wallpaperTargets, MODE_CLOSING); mRecentsView.setTransitionedFromApp(!targetSet.isAnimatingHome()); RemoteAnimationTargetCompat recentsTarget = null; RemoteAnimationTargetCompat closingAppTarget = null; - for (RemoteAnimationTargetCompat target : targetCompats) { + for (RemoteAnimationTargetCompat target : appTargets) { if (target.mode == MODE_OPENING) { recentsTarget = target; } else if (target.mode == MODE_CLOSING && target.taskId == mTargetTaskId) { @@ -157,16 +158,17 @@ final class AppToOverviewAnimationProvider imple false /* startAtFrontOfQueue */) { @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, + public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) { IconRecentsView recentsView = mRecentsView; if (!recentsView.isReadyForRemoteAnim()) { recentsView.setOnReadyForRemoteAnimCallback(() -> postAsyncCallback(handler, - () -> onCreateAnimation(targetCompats, result)) + () -> onCreateAnimation(appTargets, wallpaperTargets, result)) ); return; } - result.setAnimation(createWindowAnimation(targetCompats), context); + result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context); } }; return ActivityOptionsCompat.makeRemoteAnimation( diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 711594386f..33843977e6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -30,6 +30,9 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.SpringAnimationBuilder; @@ -38,9 +41,6 @@ import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - /** * A {@link QuickstepAppTransitionManagerImpl} that also implements recents transitions from * {@link RecentsView}. @@ -64,15 +64,16 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti @Override protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, - @NonNull RemoteAnimationTargetCompat[] targets, boolean launcherClosing) { + @NonNull RemoteAnimationTargetCompat[] appTargets, + @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) { RecentsView recentsView = mLauncher.getOverviewPanel(); boolean skipLauncherChanges = !launcherClosing; - TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); + TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets); ClipAnimationHelper helper = new ClipAnimationHelper(mLauncher); - anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets, helper) - .setDuration(RECENTS_LAUNCH_DURATION)); + anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, + wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION)); Animator childStateAnimation = null; // Found a visible recents task that matches the opening app, lets launch the app from there 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 ad90e1686e..b939898e1c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -90,11 +90,12 @@ final class AppToOverviewAnimationProvider imple /** * Create remote window animation from the currently running app to the overview panel. * - * @param targetCompats the target apps + * @param appTargets the target apps * @return animation from app to overview */ @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) { + public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { if (mRecentsView != null) { mRecentsView.setRunningTaskIconScaledDown(true); } @@ -114,8 +115,8 @@ final class AppToOverviewAnimationProvider imple return anim; } - RemoteAnimationTargetSet targetSet = - new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING); + RemoteAnimationTargetSet targetSet = new RemoteAnimationTargetSet(appTargets, + wallpaperTargets, MODE_CLOSING); // Use the top closing app to determine the insets for the animation RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mTargetTaskId); @@ -153,8 +154,8 @@ final class AppToOverviewAnimationProvider imple if (targetSet.isAnimatingHome()) { // If we are animating home, fade in the opening targets - RemoteAnimationTargetSet openingSet = - new RemoteAnimationTargetSet(targetCompats, MODE_OPENING); + RemoteAnimationTargetSet openingSet = new RemoteAnimationTargetSet(appTargets, + wallpaperTargets, MODE_OPENING); TransactionCompat transaction = new TransactionCompat(); valueAnimator.addUpdateListener((v) -> { 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 79273ead5e..af562265af 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -212,7 +212,8 @@ public class OverviewCommandHelper { return mAnimationProvider.onActivityReady(activity, wasVisible); } - private AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) { + private AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { if (LatencyTrackerCompat.isEnabled(mContext)) { LatencyTrackerCompat.logToggleRecents( (int) (SystemClock.uptimeMillis() - mToggleClickedTime)); @@ -220,7 +221,8 @@ public class OverviewCommandHelper { mListener.unregister(); - AnimatorSet animatorSet = mAnimationProvider.createWindowAnimation(targetCompats); + AnimatorSet animatorSet = mAnimationProvider.createWindowAnimation(appTargets, + wallpaperTargets); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java index 9bdc98bf8d..bebd45daa2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java @@ -16,12 +16,10 @@ package com.android.quickstep; import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION; -import static com.android.launcher3.QuickstepAppTransitionManagerImpl - .STATUS_BAR_TRANSITION_DURATION; -import static com.android.launcher3.QuickstepAppTransitionManagerImpl - .STATUS_BAR_TRANSITION_PRE_DELAY; -import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator; +import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_DURATION; +import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY; import static com.android.quickstep.TaskUtils.taskIsATargetWithMode; +import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; import android.animation.Animator; @@ -152,9 +150,10 @@ public final class RecentsActivity extends BaseRecentsActivity { true /* startAtFrontOfQueue */) { @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, - AnimationResult result) { - AnimatorSet anim = composeRecentsLaunchAnimator(taskView, targetCompats); + public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) { + AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets, + wallpaperTargets); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -174,12 +173,13 @@ public final class RecentsActivity extends BaseRecentsActivity { * Composes the animations for a launch from the recents list if possible. */ private AnimatorSet composeRecentsLaunchAnimator(TaskView taskView, - RemoteAnimationTargetCompat[] targets) { + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { AnimatorSet target = new AnimatorSet(); - boolean activityClosing = taskIsATargetWithMode(targets, getTaskId(), MODE_CLOSING); + boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING); ClipAnimationHelper helper = new ClipAnimationHelper(this); - target.play(getRecentsWindowAnimator(taskView, !activityClosing, targets, helper) - .setDuration(RECENTS_LAUNCH_DURATION)); + target.play(getRecentsWindowAnimator(taskView, !activityClosing, appTargets, + wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION)); // Found a visible recents task that matches the opening app, lets launch the app from there if (activityClosing) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java index 6897c1e7d7..00fa0f2745 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java @@ -111,14 +111,15 @@ public final class TaskViewUtils { * animation. */ public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges, - RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) { + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, final ClipAnimationHelper inOutHelper) { SyncRtSurfaceTransactionApplierCompat applier = new SyncRtSurfaceTransactionApplierCompat(v); ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams() .setSyncTransactionApplier(applier); final RemoteAnimationTargetSet targetSet = - new RemoteAnimationTargetSet(targets, MODE_OPENING); + new RemoteAnimationTargetSet(appTargets, wallpaperTargets, MODE_OPENING); targetSet.addDependentTransactionApplier(applier); final RecentsView recentsView = v.getRecentsView(); 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 4299d1a84a..71ad8ba8be 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 @@ -79,8 +79,8 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { Rect homeContentInsets, Rect minimizedHomeBounds) { mController = controller; SwipeAnimationTargetSet targetSet = new SwipeAnimationTargetSet(controller, appTargets, - homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen, - mOnFinishListener); + wallpaperTargets, homeContentInsets, minimizedHomeBounds, + mShouldMinimizeSplitScreen, mOnFinishListener); if (mCancelled) { targetSet.cancelAnimation(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java index 3619d3a0e8..3da6b78e72 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java @@ -41,10 +41,10 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet { public final Rect minimizedHomeBounds; public SwipeAnimationTargetSet(RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] targets, Rect homeContentInsets, - Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen, + RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers, + Rect homeContentInsets, Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen, Consumer onFinishListener) { - super(targets, MODE_CLOSING); + super(apps, wallpapers, MODE_CLOSING); this.controller = controller; this.homeContentInsets = homeContentInsets; this.minimizedHomeBounds = minimizedHomeBounds; @@ -62,8 +62,8 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet { */ public SwipeAnimationTargetSet cloneWithoutTargets() { return new SwipeAnimationTargetSet(controller, new RemoteAnimationTargetCompat[0], - homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen, - mOnFinishListener); + new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds, + mShouldMinimizeSplitScreen, mOnFinishListener); } public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) { diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java index a7aab6d080..96ac489d80 100644 --- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java +++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java @@ -17,8 +17,7 @@ package com.android.launcher3; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; -import static com.android.systemui.shared.recents.utilities.Utilities - .postAtFrontOfQueueAsynchronously; +import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -57,7 +56,7 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo Runnable r = () -> { finishExistingAnimation(); mAnimationResult = new AnimationResult(runnable); - onCreateAnimation(appTargets, mAnimationResult); + onCreateAnimation(appTargets, wallpaperTargets, mAnimationResult); }; if (mStartAtFrontOfQueue) { postAtFrontOfQueueAsynchronously(mHandler, r); @@ -79,7 +78,8 @@ public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCo */ @UiThread public abstract void onCreateAnimation( - RemoteAnimationTargetCompat[] targetCompats, AnimationResult result); + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result); @UiThread private void finishExistingAnimation() { diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index 38f9956203..272d1175b1 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -49,7 +49,7 @@ public class LauncherInitListener extends InternalStateHandler implements Activi // Set a one-time animation provider. After the first call, this will get cleared. // TODO: Probably also check the intended target id. CancellationSignal cancellationSignal = new CancellationSignal(); - appTransitionManager.setRemoteAnimationProvider((targets) -> { + appTransitionManager.setRemoteAnimationProvider((appTargets, wallpaperTargets) -> { // On the first call clear the reference. cancellationSignal.cancel(); @@ -57,7 +57,7 @@ public class LauncherInitListener extends InternalStateHandler implements Activi mRemoteAnimationProvider = null; if (provider != null && launcher.getStateManager().getState().overviewUi) { - return provider.createWindowAnimation(targets); + return provider.createWindowAnimation(appTargets, wallpaperTargets); } return null; }, cancellationSignal); diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java index f05fc766d5..7cd87860ac 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -202,17 +202,19 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans true /* startAtFrontOfQueue */) { @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, - AnimationResult result) { + public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) { AnimatorSet anim = new AnimatorSet(); boolean launcherClosing = - launcherIsATargetWithMode(targetCompats, MODE_CLOSING); + launcherIsATargetWithMode(appTargets, MODE_CLOSING); - if (isLaunchingFromRecents(v, targetCompats)) { - composeRecentsLaunchAnimator(anim, v, targetCompats, launcherClosing); + if (isLaunchingFromRecents(v, appTargets)) { + composeRecentsLaunchAnimator(anim, v, appTargets, wallpaperTargets, + launcherClosing); } else { - composeIconLaunchAnimator(anim, v, targetCompats, launcherClosing); + composeIconLaunchAnimator(anim, v, appTargets, wallpaperTargets, + launcherClosing); } if (launcherClosing) { @@ -255,36 +257,39 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans * * @param anim the animator set to add to * @param v the launching view - * @param targets the apps that are opening/closing + * @param appTargets the apps that are opening/closing * @param launcherClosing true if the launcher app is closing */ protected abstract void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, - @NonNull RemoteAnimationTargetCompat[] targets, boolean launcherClosing); + @NonNull RemoteAnimationTargetCompat[] appTargets, + @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing); /** * Compose the animations for a launch from the app icon. * * @param anim the animation to add to * @param v the launching view with the icon - * @param targets the list of opening/closing apps + * @param appTargets the list of opening/closing apps * @param launcherClosing true if launcher is closing */ private void composeIconLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, - @NonNull RemoteAnimationTargetCompat[] targets, boolean launcherClosing) { + @NonNull RemoteAnimationTargetCompat[] appTargets, + @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, + boolean launcherClosing) { // Set the state animation first so that any state listeners are called // before our internal listeners. mLauncher.getStateManager().setCurrentAnimation(anim); - Rect windowTargetBounds = getWindowTargetBounds(targets); + Rect windowTargetBounds = getWindowTargetBounds(appTargets); boolean isAllOpeningTargetTrs = true; - for (int i = 0; i < targets.length; i++) { - RemoteAnimationTargetCompat target = targets[i]; + for (int i = 0; i < appTargets.length; i++) { + RemoteAnimationTargetCompat target = appTargets[i]; if (target.mode == MODE_OPENING) { isAllOpeningTargetTrs &= target.isTranslucent; } if (!isAllOpeningTargetTrs) break; } - anim.play(getOpeningWindowAnimators(v, targets, windowTargetBounds, + anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, windowTargetBounds, !isAllOpeningTargetTrs)); if (launcherClosing) { Pair launcherContentAnimator = @@ -305,10 +310,10 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans * In multiwindow mode, we need to get the final size of the opening app window target to help * figure out where the floating view should animate to. */ - private Rect getWindowTargetBounds(RemoteAnimationTargetCompat[] targets) { + private Rect getWindowTargetBounds(RemoteAnimationTargetCompat[] appTargets) { Rect bounds = new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx); if (mLauncher.isInMultiWindowMode()) { - for (RemoteAnimationTargetCompat target : targets) { + for (RemoteAnimationTargetCompat target : appTargets) { if (target.mode == MODE_OPENING) { bounds.set(target.sourceContainerBounds); bounds.offsetTo(target.position.x, target.position.y); @@ -418,7 +423,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans /** * @return Animator that controls the window of the opening targets. */ - private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets, + private ValueAnimator getOpeningWindowAnimators(View v, + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, Rect windowTargetBounds, boolean toggleVisibility) { RectF bounds = new RectF(); FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v, @@ -426,8 +433,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans Rect crop = new Rect(); Matrix matrix = new Matrix(); - RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(targets, - MODE_OPENING); + RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(appTargets, + wallpaperTargets, MODE_OPENING); SyncRtSurfaceTransactionApplierCompat surfaceApplier = new SyncRtSurfaceTransactionApplierCompat(floatingView); openingTargets.addDependentTransactionApplier(surfaceApplier); @@ -551,9 +558,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans float croppedHeight = (windowTargetBounds.height() - crop.height()) * scale; float croppedWidth = (windowTargetBounds.width() - crop.width()) * scale; - SurfaceParams[] params = new SurfaceParams[targets.length]; - for (int i = targets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = targets[i]; + SurfaceParams[] params = new SurfaceParams[appTargets.length]; + for (int i = appTargets.length - 1; i >= 0; i--) { + RemoteAnimationTargetCompat target = appTargets[i]; Rect targetCrop; final float alpha; final float cornerRadius; @@ -619,7 +626,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans /** * Animator that controls the transformations of the windows when unlocking the device. */ - private Animator getUnlockWindowAnimator(RemoteAnimationTargetCompat[] targets) { + private Animator getUnlockWindowAnimator(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { SyncRtSurfaceTransactionApplierCompat surfaceApplier = new SyncRtSurfaceTransactionApplierCompat(mDragLayer); ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1); @@ -629,9 +637,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans unlockAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - SurfaceParams[] params = new SurfaceParams[targets.length]; - for (int i = targets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = targets[i]; + SurfaceParams[] params = new SurfaceParams[appTargets.length]; + for (int i = appTargets.length - 1; i >= 0; i--) { + RemoteAnimationTargetCompat target = appTargets[i]; params[i] = new SurfaceParams(target.leash, 1f, null, target.sourceContainerBounds, RemoteAnimationProvider.getLayer(target, MODE_OPENING), cornerRadius); @@ -645,7 +653,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans /** * Animator that controls the transformations of the windows the targets that are closing. */ - private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] targets) { + private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { SyncRtSurfaceTransactionApplierCompat surfaceApplier = new SyncRtSurfaceTransactionApplierCompat(mDragLayer); Matrix matrix = new Matrix(); @@ -661,9 +670,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans @Override public void onUpdate(float percent) { - SurfaceParams[] params = new SurfaceParams[targets.length]; - for (int i = targets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = targets[i]; + SurfaceParams[] params = new SurfaceParams[appTargets.length]; + for (int i = appTargets.length - 1; i >= 0; i--) { + RemoteAnimationTargetCompat target = appTargets[i]; final float alpha; final float cornerRadius; if (target.mode == MODE_CLOSING) { @@ -764,11 +773,12 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans } @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, + public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, LauncherAnimationRunner.AnimationResult result) { if (mLauncher.isDestroyed()) { AnimatorSet anim = new AnimatorSet(); - anim.play(getClosingWindowAnimators(targetCompats)); + anim.play(getClosingWindowAnimators(appTargets, wallpaperTargets)); result.setAnimation(anim, mLauncher.getApplicationContext()); return; } @@ -777,7 +787,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans // If launcher is not resumed, wait until new async-frame after resume mLauncher.addOnResumeCallback(() -> postAsyncCallback(mHandler, () -> - onCreateAnimation(targetCompats, result))); + onCreateAnimation(appTargets, wallpaperTargets, result))); return; } @@ -789,14 +799,14 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans AnimatorSet anim = null; RemoteAnimationProvider provider = mRemoteAnimationProvider; if (provider != null) { - anim = provider.createWindowAnimation(targetCompats); + anim = provider.createWindowAnimation(appTargets, wallpaperTargets); } if (anim == null) { anim = new AnimatorSet(); anim.play(mFromUnlock - ? getUnlockWindowAnimator(targetCompats) - : getClosingWindowAnimators(targetCompats)); + ? getUnlockWindowAnimator(appTargets, wallpaperTargets) + : getClosingWindowAnimators(appTargets, wallpaperTargets)); // Normally, we run the launcher content animation when we are transitioning // home, but if home is already visible, then we don't want to animate the @@ -806,7 +816,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans // targets list because it is already visible). In that case, we force // invisibility on touch down, and only reset it after the animation to home // is initialized. - if (launcherIsATargetWithMode(targetCompats, MODE_OPENING) + if (launcherIsATargetWithMode(appTargets, MODE_OPENING) || mLauncher.isForceInvisible()) { // Only register the content animation for cancellation when state changes mLauncher.getStateManager().setCurrentAnimation(anim); diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index c02df9386c..b0b5dcf751 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -165,13 +165,14 @@ public class UiFactory extends RecentsUiFactory { CancellationSignal cancellationSignal) { QuickstepAppTransitionManagerImpl appTransitionManager = (QuickstepAppTransitionManagerImpl) launcher.getAppTransitionManager(); - appTransitionManager.setRemoteAnimationProvider((targets) -> { + appTransitionManager.setRemoteAnimationProvider((appTargets, wallpaperTargets) -> { // On the first call clear the reference. cancellationSignal.cancel(); ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0); - fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(targets)); + fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets, + wallpaperTargets)); AnimatorSet anim = new AnimatorSet(); anim.play(fadeAnimation); return anim; diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java index 4503a43542..6210fc2008 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java @@ -31,16 +31,17 @@ public interface RemoteAnimationProvider { static final int Z_BOOST_BASE = 800570000; - AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targets); + AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets); default ActivityOptions toActivityOptions(Handler handler, long duration, Context context) { LauncherAnimationRunner runner = new LauncherAnimationRunner(handler, false /* startAtFrontOfQueue */) { @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, - AnimationResult result) { - result.setAnimation(createWindowAnimation(targetCompats), context); + public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) { + result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context); } }; return ActivityOptionsCompat.makeRemoteAnimation( diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java index 1229293e6e..d769248b2b 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java @@ -32,10 +32,12 @@ public class RemoteAnimationTargetSet { public final RemoteAnimationTargetCompat[] unfilteredApps; public final RemoteAnimationTargetCompat[] apps; + public final RemoteAnimationTargetCompat[] wallpapers; public final int targetMode; public final boolean hasRecents; - public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, int targetMode) { + public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, + RemoteAnimationTargetCompat[] wallpapers, int targetMode) { ArrayList filteredApps = new ArrayList<>(); boolean hasRecents = false; if (apps != null) { @@ -51,6 +53,7 @@ public class RemoteAnimationTargetSet { this.unfilteredApps = apps; this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]); + this.wallpapers = wallpapers; this.targetMode = targetMode; this.hasRecents = hasRecents; } diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java index 40dd74bbb5..1d0851c493 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java +++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java @@ -32,8 +32,9 @@ public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener { private final RemoteAnimationTargetSet mTarget; private boolean mFirstFrame = true; - public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] targets) { - mTarget = new RemoteAnimationTargetSet(targets, MODE_CLOSING); + public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets) { + mTarget = new RemoteAnimationTargetSet(appTargets, wallpaperTargets, MODE_CLOSING); } @Override From 8f90d5da8a508a73d6593164fcde2f07d86bc1b4 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 18 Sep 2019 22:29:40 -0700 Subject: [PATCH 013/109] Adding test to check view inflation during swipe up Bug: 137851409 Change-Id: Ic8e6f0b3c667051b921d1d4fad03c94122ee92e9 --- .../quickstep/ViewInflationDuringSwipeUp.java | 268 ++++++++++++++++++ tests/AndroidManifest-common.xml | 6 +- tests/res/layout/test_layout_widget_list.xml | 20 ++ .../testcomponent/ListViewService.java | 95 +++++++ .../testcomponent/TestCommandProvider.java | 130 +++++++++ .../testcomponent/TestCommandReceiver.java | 105 +------ .../launcher3/ui/AbstractLauncherUiTest.java | 33 +++ .../launcher3/ui/widget/BindWidgetTest.java | 67 ++--- 8 files changed, 578 insertions(+), 146 deletions(-) create mode 100644 quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java create mode 100644 tests/res/layout/test_layout_widget_list.xml create mode 100644 tests/src/com/android/launcher3/testcomponent/ListViewService.java create mode 100644 tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java new file mode 100644 index 0000000000..67261796f8 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java @@ -0,0 +1,268 @@ +/* + * 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.quickstep; + +import static androidx.test.InstrumentationRegistry.getContext; +import static androidx.test.InstrumentationRegistry.getInstrumentation; + +import static com.android.launcher3.testcomponent.TestCommandReceiver.EXTRA_VALUE; +import static com.android.launcher3.testcomponent.TestCommandReceiver.SET_LIST_VIEW_SERVICE_BINDER; +import static com.android.launcher3.ui.widget.BindWidgetTest.createWidgetInfo; +import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; + +import android.appwidget.AppWidgetManager; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.RemoteViews; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.tapl.Background; +import com.android.launcher3.testcomponent.ListViewService; +import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory; +import com.android.launcher3.testcomponent.TestCommandReceiver; +import com.android.launcher3.ui.TaplTestsLauncher3; +import com.android.launcher3.ui.TestViewHelpers; +import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Field; +import java.util.function.IntConsumer; + +/** + * Test to verify view inflation does not happen during swipe up. + * To verify view inflation, we setup a dummy ViewConfiguration and check if any call to that class + * does from a View.init method or not. + * + * Alternative approaches considered: + * Overriding LayoutInflater: This does not cover views initialized + * directly (ex: new LinearLayout) + * Using ExtendedMockito: Mocking static methods from platform classes (loaded in zygote) makes + * the main thread extremely slow and untestable + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +public class ViewInflationDuringSwipeUp extends AbstractQuickStepTest { + + private ContentResolver mResolver; + private SparseArray mConfigMap; + private InitTracker mInitTracker; + + @Before + public void setUp() throws Exception { + super.setUp(); + TaplTestsLauncher3.initialize(this); + + mResolver = mTargetContext.getContentResolver(); + LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); + + // Get static configuration map + Field field = ViewConfiguration.class.getDeclaredField("sConfigurations"); + field.setAccessible(true); + mConfigMap = (SparseArray) field.get(null); + + mInitTracker = new InitTracker(); + } + + @Test + @NavigationModeSwitch(mode = ZERO_BUTTON) + public void testSwipeUpFromApp() throws Exception { + try { + // Go to overview once so that all views are initialized and cached + startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); + mLauncher.getBackground().switchToOverview().dismissAllTasks(); + + // Track view creations + mInitTracker.startTracking(); + + startTestActivity(2); + mLauncher.getBackground().switchToOverview(); + + assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount); + } finally { + mConfigMap.clear(); + } + } + + @Test + @NavigationModeSwitch(mode = ZERO_BUTTON) + public void testSwipeUpFromApp_widget_update() { + String dummyText = "Some random dummy text"; + + executeSwipeUpTestWithWidget( + widgetId -> { }, + widgetId -> AppWidgetManager.getInstance(getContext()) + .updateAppWidget(widgetId, createMainWidgetViews(dummyText)), + dummyText); + } + + @Test + @NavigationModeSwitch(mode = ZERO_BUTTON) + public void testSwipeUp_with_list_widgets() { + SimpleViewsFactory viewFactory = new SimpleViewsFactory(); + viewFactory.viewCount = 1; + Bundle args = new Bundle(); + args.putBinder(EXTRA_VALUE, viewFactory.toBinder()); + TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, args); + + try { + executeSwipeUpTestWithWidget( + widgetId -> { + // Initialize widget + RemoteViews views = createMainWidgetViews("List widget title"); + views.setRemoteAdapter(android.R.id.list, + new Intent(getContext(), ListViewService.class)); + AppWidgetManager.getInstance(getContext()).updateAppWidget(widgetId, views); + verifyWidget(viewFactory.getLabel(0)); + }, + widgetId -> { + // Update widget + viewFactory.viewCount = 2; + AppWidgetManager.getInstance(getContext()) + .notifyAppWidgetViewDataChanged(widgetId, android.R.id.list); + }, + viewFactory.getLabel(1) + ); + } finally { + TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, new Bundle()); + } + } + + private void executeSwipeUpTestWithWidget(IntConsumer widgetIdCreationCallback, + IntConsumer updateBeforeSwipeUp, String finalWidgetText) { + try { + // Clear all existing data + LauncherSettings.Settings.call(mResolver, + LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); + LauncherSettings.Settings.call(mResolver, + LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG); + LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false); + LauncherAppWidgetInfo item = createWidgetInfo(info, true); + + addItemToScreen(item); + assertTrue("Widget is not present", + mLauncher.pressHome().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null); + int widgetId = item.appWidgetId; + + // Verify widget id + widgetIdCreationCallback.accept(widgetId); + + // Go to overview once so that all views are initialized and cached + startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); + mLauncher.getBackground().switchToOverview().dismissAllTasks(); + + // Track view creations + mInitTracker.startTracking(); + + startTestActivity(2); + Background background = mLauncher.getBackground(); + + // Update widget + updateBeforeSwipeUp.accept(widgetId); + + background.switchToOverview(); + assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount); + + // Widget is updated when going home + mInitTracker.disableLog(); + mLauncher.pressHome(); + verifyWidget(finalWidgetText); + assertNotEquals(1, mInitTracker.viewInitCount); + } finally { + mConfigMap.clear(); + } + } + + private void verifyWidget(String text) { + assertNotNull("Widget not updated", + UiDevice.getInstance(getInstrumentation()) + .wait(Until.findObject(By.text(text)), DEFAULT_UI_TIMEOUT)); + } + + private RemoteViews createMainWidgetViews(String title) { + Context c = getContext(); + int layoutId = c.getResources().getIdentifier( + "test_layout_widget_list", "layout", c.getPackageName()); + RemoteViews views = new RemoteViews(c.getPackageName(), layoutId); + views.setTextViewText(android.R.id.text1, title); + return views; + } + + private class InitTracker implements Answer { + + public int viewInitCount = 0; + + public boolean log = true; + + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Exception ex = new Exception(); + + boolean found = false; + for (StackTraceElement ste : ex.getStackTrace()) { + if ("".equals(ste.getMethodName()) + && View.class.getName().equals(ste.getClassName())) { + found = true; + break; + } + } + if (found) { + viewInitCount++; + if (log) { + Log.d("InitTracker", "New view inflated", ex); + } + + } + return invocation.callRealMethod(); + } + + public void disableLog() { + log = false; + } + + public void startTracking() { + ViewConfiguration vc = ViewConfiguration.get(mTargetContext); + ViewConfiguration spyVC = spy(vc); + mConfigMap.put(mConfigMap.keyAt(mConfigMap.indexOfValue(vc)), spyVC); + doAnswer(this).when(spyVC).getScaledTouchSlop(); + } + } +} diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index c6f55a7178..0b74dc4096 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -73,8 +73,12 @@ + + diff --git a/tests/res/layout/test_layout_widget_list.xml b/tests/res/layout/test_layout_widget_list.xml new file mode 100644 index 0000000000..0152040f7e --- /dev/null +++ b/tests/res/layout/test_layout_widget_list.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/tests/src/com/android/launcher3/testcomponent/ListViewService.java b/tests/src/com/android/launcher3/testcomponent/ListViewService.java new file mode 100644 index 0000000000..3da20e0991 --- /dev/null +++ b/tests/src/com/android/launcher3/testcomponent/ListViewService.java @@ -0,0 +1,95 @@ +/* + * 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.testcomponent; + +import android.content.Intent; +import android.os.IBinder; +import android.widget.RemoteViews; +import android.widget.RemoteViewsService; + +public class ListViewService extends RemoteViewsService { + + public static IBinder sBinderForTest; + + @Override + public RemoteViewsFactory onGetViewFactory(Intent intent) { + return new SimpleViewsFactory(); + } + + @Override + public IBinder onBind(Intent intent) { + return sBinderForTest != null ? sBinderForTest : super.onBind(intent); + } + + public static class SimpleViewsFactory implements RemoteViewsFactory { + + public int viewCount = 0; + + @Override + public void onCreate() { } + + @Override + public void onDataSetChanged() { } + + @Override + public void onDestroy() { } + + @Override + public int getCount() { + return viewCount; + } + + @Override + public RemoteViews getViewAt(int i) { + RemoteViews views = new RemoteViews("android", android.R.layout.simple_list_item_1); + views.setTextViewText(android.R.id.text1, getLabel(i)); + return views; + } + + public String getLabel(int i) { + return "Item " + i; + } + + @Override + public RemoteViews getLoadingView() { + return null; + } + + @Override + public int getViewTypeCount() { + return 1; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + public IBinder toBinder() { + return new RemoteViewsService() { + @Override + public RemoteViewsFactory onGetViewFactory(Intent intent) { + return SimpleViewsFactory.this; + } + }.onBind(new Intent("dummy_intent")); + } + } +} diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java b/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java new file mode 100644 index 0000000000..7682e0771c --- /dev/null +++ b/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java @@ -0,0 +1,130 @@ +/* + * 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.testcomponent; + +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.PackageManager.DONT_KILL_APP; +import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; + +import static com.android.launcher3.testcomponent.TestCommandReceiver.DISABLE_TEST_LAUNCHER; +import static com.android.launcher3.testcomponent.TestCommandReceiver.ENABLE_TEST_LAUNCHER; +import static com.android.launcher3.testcomponent.TestCommandReceiver.EXTRA_VALUE; +import static com.android.launcher3.testcomponent.TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE; +import static com.android.launcher3.testcomponent.TestCommandReceiver.KILL_PROCESS; +import static com.android.launcher3.testcomponent.TestCommandReceiver.SET_LIST_VIEW_SERVICE_BINDER; + +import android.app.Activity; +import android.app.ActivityManager; +import android.content.ComponentName; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.util.Base64; + +import com.android.launcher3.tapl.TestHelpers; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class TestCommandProvider extends ContentProvider { + + @Override + public boolean onCreate() { + return true; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public String getType(Uri uri) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public Bundle call(String method, String arg, Bundle extras) { + switch (method) { + case ENABLE_TEST_LAUNCHER: { + getContext().getPackageManager().setComponentEnabledSetting( + new ComponentName(getContext(), TestLauncherActivity.class), + COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP); + return null; + } + case DISABLE_TEST_LAUNCHER: { + getContext().getPackageManager().setComponentEnabledSetting( + new ComponentName(getContext(), TestLauncherActivity.class), + COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP); + return null; + } + case KILL_PROCESS: { + ((ActivityManager) getContext().getSystemService(Activity.ACTIVITY_SERVICE)) + .killBackgroundProcesses(arg); + return null; + } + + case GET_SYSTEM_HEALTH_MESSAGE: { + final Bundle response = new Bundle(); + response.putString("result", TestHelpers.getSystemHealthMessage(getContext())); + return response; + } + + case SET_LIST_VIEW_SERVICE_BINDER: { + ListViewService.sBinderForTest = extras.getBinder(EXTRA_VALUE); + return null; + } + } + return super.call(method, arg, extras); + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + String path = Base64.encodeToString(uri.getPath().getBytes(), + Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP); + File file = new File(getContext().getCacheDir(), path); + if (!file.exists()) { + // Create an empty file so that we can pass its descriptor + try { + file.createNewFile(); + } catch (IOException e) { + } + } + + return ParcelFileDescriptor.open(file, MODE_READ_WRITE); + } +} diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java index 6a6916eec3..eb6c3ed783 100644 --- a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java +++ b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java @@ -15,125 +15,36 @@ */ package com.android.launcher3.testcomponent; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.DONT_KILL_APP; -import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; - -import android.app.Activity; -import android.app.ActivityManager; import android.app.Instrumentation; -import android.content.ComponentName; -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; import android.net.Uri; import android.os.Bundle; -import android.os.ParcelFileDescriptor; -import android.util.Base64; import androidx.test.InstrumentationRegistry; -import com.android.launcher3.tapl.TestHelpers; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; - /** * Content provider to receive commands from tests */ -public class TestCommandReceiver extends ContentProvider { +public class TestCommandReceiver { public static final String ENABLE_TEST_LAUNCHER = "enable-test-launcher"; public static final String DISABLE_TEST_LAUNCHER = "disable-test-launcher"; public static final String KILL_PROCESS = "kill-process"; public static final String GET_SYSTEM_HEALTH_MESSAGE = "get-system-health-message"; + public static final String SET_LIST_VIEW_SERVICE_BINDER = "set-list-view-service-binder"; - @Override - public boolean onCreate() { - return true; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public String getType(Uri uri) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public Bundle call(String method, String arg, Bundle extras) { - switch (method) { - case ENABLE_TEST_LAUNCHER: { - getContext().getPackageManager().setComponentEnabledSetting( - new ComponentName(getContext(), TestLauncherActivity.class), - COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP); - return null; - } - case DISABLE_TEST_LAUNCHER: { - getContext().getPackageManager().setComponentEnabledSetting( - new ComponentName(getContext(), TestLauncherActivity.class), - COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP); - return null; - } - case KILL_PROCESS: { - ((ActivityManager) getContext().getSystemService(Activity.ACTIVITY_SERVICE)). - killBackgroundProcesses(arg); - return null; - } - - case GET_SYSTEM_HEALTH_MESSAGE: { - final Bundle response = new Bundle(); - response.putString("result", TestHelpers.getSystemHealthMessage(getContext())); - return response; - } - } - return super.call(method, arg, extras); - } + public static final String EXTRA_VALUE = "value"; public static Bundle callCommand(String command) { return callCommand(command, null); } public static Bundle callCommand(String command, String arg) { + return callCommand(command, arg, null); + } + + public static Bundle callCommand(String command, String arg, Bundle extras) { Instrumentation inst = InstrumentationRegistry.getInstrumentation(); Uri uri = Uri.parse("content://" + inst.getContext().getPackageName() + ".commands"); - return inst.getTargetContext().getContentResolver().call(uri, command, arg, null); - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - String path = Base64.encodeToString(uri.getPath().getBytes(), - Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP); - File file = new File(getContext().getCacheDir(), path); - if (!file.exists()) { - // Create an empty file so that we can pass its descriptor - try { - file.createNewFile(); - } catch (IOException e) { - } - } - - return ParcelFileDescriptor.open(file, MODE_READ_WRITE); + return inst.getTargetContext().getContentResolver().call(uri, command, arg, extras); } } diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 1fac7081b7..54d81bb179 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -17,6 +17,7 @@ package com.android.launcher3.ui; import static androidx.test.InstrumentationRegistry.getInstrumentation; +import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; import static com.android.launcher3.tapl.LauncherInstrumentation.ContainerType; import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -27,6 +28,7 @@ import static java.lang.System.exit; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -43,6 +45,7 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.Until; +import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; @@ -56,6 +59,7 @@ import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.tapl.TestHelpers; import com.android.launcher3.testcomponent.TestCommandReceiver; import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.LooperExecutor; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Wait; @@ -230,6 +234,35 @@ public abstract class AbstractLauncherUiTest { }); } + /** + * Adds {@param item} on the homescreen on the 0th screen + */ + protected void addItemToScreen(ItemInfo item) { + ContentResolver resolver = mTargetContext.getContentResolver(); + int screenId = FIRST_SCREEN_ID; + // Update the screen id counter for the provider. + LauncherSettings.Settings.call(resolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID); + + if (screenId > FIRST_SCREEN_ID) { + screenId = FIRST_SCREEN_ID; + } + + // Insert the item + ContentWriter writer = new ContentWriter(mTargetContext); + item.id = LauncherSettings.Settings.call( + resolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID) + .getInt(LauncherSettings.Settings.EXTRA_VALUE); + item.screenId = screenId; + item.onAddToDatabase(writer); + writer.put(LauncherSettings.Favorites._ID, item.id); + resolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(mTargetContext)); + resetLoaderState(); + + // Launch the home activity + mDevice.pressHome(); + waitForModelLoaded(); + } + /** * Runs the callback on the UI thread and returns the result. */ diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index e6348d9c02..ac87148633 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -15,7 +15,9 @@ */ package com.android.launcher3.ui.widget; -import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; +import static androidx.test.InstrumentationRegistry.getTargetContext; + +import static com.android.launcher3.widget.WidgetHostViewLoader.getDefaultOptionsForWidget; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -25,6 +27,7 @@ import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.ContentResolver; +import android.content.Context; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; @@ -43,11 +46,8 @@ import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.tapl.Workspace; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TestViewHelpers; -import com.android.launcher3.util.ContentWriter; -import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.rule.ShellCommandRule; import com.android.launcher3.widget.PendingAddWidgetInfo; -import com.android.launcher3.widget.WidgetHostViewLoader; import org.junit.After; import org.junit.Before; @@ -57,7 +57,6 @@ import org.junit.runner.RunWith; import java.util.HashSet; import java.util.Set; -import java.util.function.Consumer; /** * Tests for bind widget flow. @@ -72,7 +71,6 @@ public class BindWidgetTest extends AbstractLauncherUiTest { public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); private ContentResolver mResolver; - private AppWidgetManagerCompat mWidgetManager; // Objects created during test, which should be cleaned up in the end. private Cursor mCursor; @@ -85,7 +83,6 @@ public class BindWidgetTest extends AbstractLauncherUiTest { super.setUp(); mResolver = mTargetContext.getContentResolver(); - mWidgetManager = AppWidgetManagerCompat.getInstance(mTargetContext); // Clear all existing data LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); @@ -108,7 +105,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, true); LauncherAppWidgetInfo item = createWidgetInfo(info, true); - setupContents(item); + addItemToScreen(item); verifyWidgetPresent(info); } @@ -117,7 +114,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false); LauncherAppWidgetInfo item = createWidgetInfo(info, true); - setupContents(item); + addItemToScreen(item); verifyWidgetPresent(info); } @@ -127,7 +124,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetInfo item = createWidgetInfo(info, false); item.appWidgetId = -33; - setupContents(item); + addItemToScreen(item); final Workspace workspace = mLauncher.getWorkspace(); // Item deleted from db @@ -148,7 +145,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetInfo item = createWidgetInfo(info, false); item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID; - setupContents(item); + addItemToScreen(item); verifyWidgetPresent(info); } @@ -161,7 +158,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetInfo item = createWidgetInfo(info, false); item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID; - setupContents(item); + addItemToScreen(item); verifyPendingWidgetPresent(); // Item deleted from db @@ -183,7 +180,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; - setupContents(item); + addItemToScreen(item); assertTrue("Pending widget exists", mLauncher.getWorkspace().tryGetPendingWidget(0) == null); @@ -202,7 +199,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { | LauncherAppWidgetInfo.FLAG_RESTORE_STARTED | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; - setupContents(item); + addItemToScreen(item); verifyPendingWidgetPresent(); // Verify item still exists in db @@ -230,7 +227,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller(); mSessionId = installer.createSession(params); - setupContents(item); + addItemToScreen(item); verifyPendingWidgetPresent(); // Verify item still exists in db @@ -245,35 +242,6 @@ public class BindWidgetTest extends AbstractLauncherUiTest { & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID); } - /** - * Adds {@param item} on the homescreen on the 0th screen at 0,0, and verifies that the - * widget class is displayed on the homescreen. - */ - private void setupContents(LauncherAppWidgetInfo item) { - int screenId = FIRST_SCREEN_ID; - // Update the screen id counter for the provider. - LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID); - - if (screenId > FIRST_SCREEN_ID) { - screenId = FIRST_SCREEN_ID; - } - - // Insert the item - ContentWriter writer = new ContentWriter(mTargetContext); - item.id = LauncherSettings.Settings.call( - mResolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID) - .getInt(LauncherSettings.Settings.EXTRA_VALUE); - item.screenId = screenId; - item.onAddToDatabase(writer); - writer.put(LauncherSettings.Favorites._ID, item.id); - mResolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(mTargetContext)); - resetLoaderState(); - - // Launch the home activity - mDevice.pressHome(); - waitForModelLoaded(); - } - private void verifyWidgetPresent(LauncherAppWidgetProviderInfo info) { assertTrue("Widget is not present", mLauncher.getWorkspace().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null); @@ -289,8 +257,10 @@ public class BindWidgetTest extends AbstractLauncherUiTest { * @param bindWidget if true the info is bound and a valid widgetId is assigned to * the LauncherAppWidgetInfo */ - private LauncherAppWidgetInfo createWidgetInfo( + public static LauncherAppWidgetInfo createWidgetInfo( LauncherAppWidgetProviderInfo info, boolean bindWidget) { + Context targetContext = getTargetContext(); + LauncherAppWidgetInfo item = new LauncherAppWidgetInfo( LauncherAppWidgetInfo.NO_ID, info.provider); item.spanX = info.minSpanX; @@ -308,11 +278,12 @@ public class BindWidgetTest extends AbstractLauncherUiTest { pendingInfo.spanY = item.spanY; pendingInfo.minSpanX = item.minSpanX; pendingInfo.minSpanY = item.minSpanY; - Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(mTargetContext, pendingInfo); + Bundle options = getDefaultOptionsForWidget(targetContext, pendingInfo); - AppWidgetHost host = new LauncherAppWidgetHost(mTargetContext); + AppWidgetHost host = new LauncherAppWidgetHost(targetContext); int widgetId = host.allocateAppWidgetId(); - if (!mWidgetManager.bindAppWidgetIdIfAllowed(widgetId, info, options)) { + if (!AppWidgetManagerCompat.getInstance(targetContext) + .bindAppWidgetIdIfAllowed(widgetId, info, options)) { host.deleteAppWidgetId(widgetId); throw new IllegalArgumentException("Unable to bind widget id"); } From fc041efe92c40f0c53c8f02b88a5753fcb7a2a38 Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 20 Sep 2019 17:23:11 -0700 Subject: [PATCH 014/109] Adding recognition of R launcher builds for test stability rule Change-Id: Icf1251c02d328e634bf4d5c951dd53f203905838 --- .../launcher3/util/rule/TestStabilityRule.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java index 8391ae713c..8feadbee9e 100644 --- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java +++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java @@ -37,11 +37,11 @@ public class TestStabilityRule implements TestRule { private static final String TAG = "TestStabilityRule"; private static final Pattern LAUNCHER_BUILD = Pattern.compile("^(" - + "(?BuildFromAndroidStudio)|" - + "(?[0-9]+-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+)|" - + "(?[0-9]+-P[0-9]+)|" - + "(?[0-9]+-[0-9]+|" - + "(?[0-9]+))" + + "(?(BuildFromAndroidStudio|" + + "([0-9]+|[A-Z])-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+))|" + + "(?([0-9]+|[A-Z])-P[0-9]+)|" + + "(?([0-9]+|[A-Z])+-[0-9]+|" + + "(?([0-9]+|[A-Z])+))" + ")$"); private static final Pattern PLATFORM_BUILD = Pattern.compile("^(" @@ -80,8 +80,7 @@ public class TestStabilityRule implements TestRule { if (!launcherBuildMatcher.find()) { Log.e(TAG, "Match not found"); - } else if (launcherBuildMatcher.group("androidStudio") != null - || launcherBuildMatcher.group("commandLine") != null) { + } else if (launcherBuildMatcher.group("local") != null) { launcherLocalBuild = true; } else if (launcherBuildMatcher.group("presubmit") != null) { launcherUnbundledPresubmit = true; From 6a585df8d1a9407a6e8e427b663a426176ec5f3d Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 19 Sep 2019 19:26:09 -0700 Subject: [PATCH 015/109] Not using dropbox entries before the test start for diagnostics Change-Id: Ia060b5d2b98ea9ea3b6e61ae11d610f1a888d7a0 --- .../launcher3/testcomponent/TestCommandProvider.java | 3 ++- .../android/launcher3/ui/AbstractLauncherUiTest.java | 5 +++-- .../launcher3/tapl/LauncherInstrumentation.java | 11 ++++++----- .../tapl/com/android/launcher3/tapl/TestHelpers.java | 8 ++++---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java b/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java index 7682e0771c..f9981a9bfe 100644 --- a/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java +++ b/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java @@ -100,7 +100,8 @@ public class TestCommandProvider extends ContentProvider { case GET_SYSTEM_HEALTH_MESSAGE: { final Bundle response = new Bundle(); - response.putString("result", TestHelpers.getSystemHealthMessage(getContext())); + response.putString("result", + TestHelpers.getSystemHealthMessage(getContext(), Long.parseLong(arg))); return response; } diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 54d81bb179..9bce96c2e1 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -111,8 +111,9 @@ public abstract class AbstractLauncherUiTest { } if (TestHelpers.isInLauncherProcess()) { Utilities.enableRunningInTestHarnessForTests(); - mLauncher.setSystemHealthSupplier(() -> TestCommandReceiver.callCommand( - TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE).getString("result")); + mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand( + TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()). + getString("result")); mLauncher.setOnSettledStateAction( containerType -> executeOnLauncher( launcher -> diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 1c81b1096f..f6fffdd886 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -73,7 +73,7 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import java.util.function.Supplier; +import java.util.function.Function; /** * The main tapl object. The only object that can be explicitly constructed by the using code. It @@ -84,6 +84,7 @@ public final class LauncherInstrumentation { private static final String TAG = "Tapl"; private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20; private static final int GESTURE_STEP_MS = 16; + private static long START_TIME = System.currentTimeMillis(); // Types for launcher containers that the user is interacting with. "Background" is a // pseudo-container corresponding to inactive launcher covered by another app. @@ -134,7 +135,7 @@ public final class LauncherInstrumentation { private int mExpectedRotation = Surface.ROTATION_0; private final Uri mTestProviderUri; private final Deque mDiagnosticContext = new LinkedList<>(); - private Supplier mSystemHealthSupplier; + private Function mSystemHealthSupplier; private Consumer mOnSettledStateAction; @@ -296,7 +297,7 @@ public final class LauncherInstrumentation { return "Background"; } - public void setSystemHealthSupplier(Supplier supplier) { + public void setSystemHealthSupplier(Function supplier) { this.mSystemHealthSupplier = supplier; } @@ -316,8 +317,8 @@ public final class LauncherInstrumentation { } return mSystemHealthSupplier != null - ? mSystemHealthSupplier.get() - : TestHelpers.getSystemHealthMessage(getContext()); + ? mSystemHealthSupplier.apply(START_TIME) + : TestHelpers.getSystemHealthMessage(getContext(), START_TIME); } private void fail(String message) { diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java index ba0dd73206..d0e3e922cb 100644 --- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java +++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java @@ -106,11 +106,11 @@ public class TestHelpers { return ret.toString(); } - private static String checkCrash(Context context, String label) { + private static String checkCrash(Context context, String label, long startTime) { DropBoxManager dropbox = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE); Assert.assertNotNull("Unable access the DropBoxManager service", dropbox); - long timestamp = System.currentTimeMillis() - 5 * 60000; + long timestamp = startTime; DropBoxManager.Entry entry; StringBuilder errorDetails = new StringBuilder(); while (null != (entry = dropbox.getNextEntry(label, timestamp))) { @@ -128,7 +128,7 @@ public class TestHelpers { return errorDetails.length() != 0 ? errorDetails.toString() : null; } - public static String getSystemHealthMessage(Context context) { + public static String getSystemHealthMessage(Context context, long startTime) { try { StringBuilder errors = new StringBuilder(); @@ -144,7 +144,7 @@ public class TestHelpers { }; for (String label : labels) { - final String crash = checkCrash(context, label); + final String crash = checkCrash(context, label, startTime); if (crash != null) errors.append(crash); } From 3bdba615428b384d5130cdaf775c315340c3afbd Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 19 Sep 2019 19:26:09 -0700 Subject: [PATCH 016/109] Not using dropbox entries before the test start for diagnostics Change-Id: Ieb48d969d86a855c91109f4ace0d636fa01aafc7 Merged-in: Ia060b5d2b98ea9ea3b6e61ae11d610f1a888d7a0 --- .../launcher3/testcomponent/TestCommandReceiver.java | 3 ++- .../android/launcher3/ui/AbstractLauncherUiTest.java | 5 +++-- .../launcher3/tapl/LauncherInstrumentation.java | 11 ++++++----- .../tapl/com/android/launcher3/tapl/TestHelpers.java | 8 ++++---- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java index 6a6916eec3..42460961bf 100644 --- a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java +++ b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java @@ -104,7 +104,8 @@ public class TestCommandReceiver extends ContentProvider { case GET_SYSTEM_HEALTH_MESSAGE: { final Bundle response = new Bundle(); - response.putString("result", TestHelpers.getSystemHealthMessage(getContext())); + response.putString("result", + TestHelpers.getSystemHealthMessage(getContext(), Long.parseLong(arg))); return response; } } diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 840fdd26c4..1f4ba1af0c 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -105,8 +105,9 @@ public abstract class AbstractLauncherUiTest { } if (TestHelpers.isInLauncherProcess()) { Utilities.enableRunningInTestHarnessForTests(); - mLauncher.setSystemHealthSupplier(() -> TestCommandReceiver.callCommand( - TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE).getString("result")); + mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand( + TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()). + getString("result")); mLauncher.setOnSettledStateAction( containerType -> executeOnLauncher( launcher -> diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 15615fc6b6..65208ceb58 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -73,7 +73,7 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import java.util.function.Supplier; +import java.util.function.Function; /** * The main tapl object. The only object that can be explicitly constructed by the using code. It @@ -84,6 +84,7 @@ public final class LauncherInstrumentation { private static final String TAG = "Tapl"; private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20; private static final int GESTURE_STEP_MS = 16; + private static long START_TIME = System.currentTimeMillis(); // Types for launcher containers that the user is interacting with. "Background" is a // pseudo-container corresponding to inactive launcher covered by another app. @@ -134,7 +135,7 @@ public final class LauncherInstrumentation { private int mExpectedRotation = Surface.ROTATION_0; private final Uri mTestProviderUri; private final Deque mDiagnosticContext = new LinkedList<>(); - private Supplier mSystemHealthSupplier; + private Function mSystemHealthSupplier; private Consumer mOnSettledStateAction; @@ -296,7 +297,7 @@ public final class LauncherInstrumentation { return "Background"; } - public void setSystemHealthSupplier(Supplier supplier) { + public void setSystemHealthSupplier(Function supplier) { this.mSystemHealthSupplier = supplier; } @@ -316,8 +317,8 @@ public final class LauncherInstrumentation { } return mSystemHealthSupplier != null - ? mSystemHealthSupplier.get() - : TestHelpers.getSystemHealthMessage(getContext()); + ? mSystemHealthSupplier.apply(START_TIME) + : TestHelpers.getSystemHealthMessage(getContext(), START_TIME); } private void fail(String message) { diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java index a089a527ef..05c987be29 100644 --- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java +++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java @@ -101,11 +101,11 @@ public class TestHelpers { return ret.toString(); } - private static String checkCrash(Context context, String label) { + private static String checkCrash(Context context, String label, long startTime) { DropBoxManager dropbox = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE); Assert.assertNotNull("Unable access the DropBoxManager service", dropbox); - long timestamp = System.currentTimeMillis() - 5 * 60000; + long timestamp = startTime; DropBoxManager.Entry entry; StringBuilder errorDetails = new StringBuilder(); while (null != (entry = dropbox.getNextEntry(label, timestamp))) { @@ -123,7 +123,7 @@ public class TestHelpers { return errorDetails.length() != 0 ? errorDetails.toString() : null; } - public static String getSystemHealthMessage(Context context) { + public static String getSystemHealthMessage(Context context, long startTime) { try { StringBuilder errors = new StringBuilder(); @@ -139,7 +139,7 @@ public class TestHelpers { }; for (String label : labels) { - final String crash = checkCrash(context, label); + final String crash = checkCrash(context, label, startTime); if (crash != null) errors.append(crash); } From af6daa2873a82e9222cad3589061e5c2b26702b5 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 18 Sep 2019 22:18:03 +0000 Subject: [PATCH 017/109] Revert "Revert "support scroll backward to minus one screen via voice/switch access"" This reverts commit 3ad4ace203c73aebac98010812703dbb6879d55d. Reason for revert: roll forward and bugfixes Change-Id: Icd56cdeddb3baf9819700cc567c04af0905825ef --- src/com/android/launcher3/PagedView.java | 22 +++++++++++++++------- src/com/android/launcher3/Workspace.java | 7 +++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index a99c7c28f9..5c790f3797 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1548,7 +1548,7 @@ public abstract class PagedView extends ViewGrou snapToPage(getNextPage() - 1); return true; } - return false; + return onOverscroll(-getMeasuredWidth()); } public boolean scrollRight() { @@ -1556,7 +1556,15 @@ public abstract class PagedView extends ViewGrou snapToPage(getNextPage() + 1); return true; } - return false; + return onOverscroll(getMeasuredWidth()); + } + + protected boolean onOverscroll(int amount) { + if (!mAllowOverScroll) return false; + onScrollInteractionBegin(); + overScroll(amount); + onScrollInteractionEnd(); + return true; } @Override @@ -1576,8 +1584,9 @@ public abstract class PagedView extends ViewGrou public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); final boolean pagesFlipped = isPageOrderFlipped(); - info.setScrollable(getPageCount() > 1); - if (getCurrentPage() < getPageCount() - 1) { + int offset = (mAllowOverScroll ? 0 : 1); + info.setScrollable(getPageCount() > offset); + if (getCurrentPage() < getPageCount() - offset) { info.addAction(pagesFlipped ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); @@ -1585,7 +1594,7 @@ public abstract class PagedView extends ViewGrou AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT); } - if (getCurrentPage() > 0) { + if (getCurrentPage() >= offset) { info.addAction(pagesFlipped ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); @@ -1593,7 +1602,6 @@ public abstract class PagedView extends ViewGrou AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT); } - // Accessibility-wise, PagedView doesn't support long click, so disabling it. // Besides disabling the accessibility long-click, this also prevents this view from getting // accessibility focus. @@ -1612,7 +1620,7 @@ public abstract class PagedView extends ViewGrou @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); - event.setScrollable(getPageCount() > 1); + event.setScrollable(mAllowOverScroll || getPageCount() > 1); } @Override diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index f9201d04c7..1cb15db98e 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1034,6 +1034,13 @@ public class Workspace extends PagedView } } + @Override + protected boolean onOverscroll(int amount) { + // Enforce overscroll on -1 direction + if ((amount > 0 && !mIsRtl) || (amount < 0 && mIsRtl)) return false; + return super.onOverscroll(amount); + } + @Override protected boolean shouldFlingForVelocity(int velocityX) { // When the overlay is moving, the fling or settle transition is controlled by the overlay. From 7752023c08643554ef422447c8ed841476137f8f Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 18 Sep 2019 17:10:54 -0700 Subject: [PATCH 018/109] fix test for a11y change in supporting -1 page Bug: 140406263 Change-Id: I0a39db135a5e5b0fe570ace55a368a7f4b6cb453 Test: run TaplTestLauncher3 locally --- src/com/android/launcher3/PagedView.java | 7 +++++++ .../launcher3/testing/TestInformationHandler.java | 11 ++++++++++- src/com/android/launcher3/testing/TestProtocol.java | 2 ++ tests/tapl/com/android/launcher3/tapl/Workspace.java | 11 ++++++----- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 5c790f3797..34b102c0b7 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1708,4 +1708,11 @@ public abstract class PagedView extends ViewGrou mTmpIntPair[1] = rightChild; return mTmpIntPair; } + + /** + * Returns true if overscroll is allowed, otherwise false. + */ + public boolean allowOverScroll() { + return mAllowOverScroll; + } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 0d1d1a6709..d62b591b8c 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -15,9 +15,10 @@ */ package com.android.launcher3.testing; -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static android.graphics.Bitmap.Config.ARGB_8888; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; @@ -81,6 +82,14 @@ public class TestInformationHandler implements ResourceBasedOverride { break; } + case TestProtocol.REQUEST_DOES_WORKSPACE_HAVE_SECOND_PAGE: { + if (mLauncher == null) return null; + + response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, + mLauncher.getWorkspace().getPageCount() > 1); + break; + } + case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: { response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true); break; diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 19c557c9ff..a68a140ef3 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -66,6 +66,8 @@ public final class TestProtocol { "all-apps-to-overview-swipe-height"; public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT = "home-to-all-apps-swipe-height"; + public static final String REQUEST_DOES_WORKSPACE_HAVE_SECOND_PAGE = + "does-workspace-have-second-page"; public static final String REQUEST_HOTSEAT_TOP = "hotseat-top"; public static final String REQUEST_IS_LAUNCHER_INITIALIZED = "is-launcher-initialized"; public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list"; diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 510ea14091..d556afc9ba 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -22,6 +22,7 @@ import static junit.framework.TestCase.assertTrue; import android.graphics.Point; import android.graphics.Rect; +import android.os.Bundle; import android.os.SystemClock; import android.view.KeyEvent; import android.view.MotionEvent; @@ -125,7 +126,7 @@ public final class Workspace extends Home { */ public void ensureWorkspaceIsScrollable() { final UiObject2 workspace = verifyActiveContainer(); - if (!isWorkspaceScrollable(workspace)) { + if (!isWorkspaceScrollable()) { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "dragging icon to a second page of workspace to make it scrollable")) { dragIconToWorkspace( @@ -137,12 +138,12 @@ public final class Workspace extends Home { verifyActiveContainer(); } } - assertTrue("Home screen workspace didn't become scrollable", - isWorkspaceScrollable(workspace)); + assertTrue("Home screen workspace didn't become scrollable", isWorkspaceScrollable()); } - private boolean isWorkspaceScrollable(UiObject2 workspace) { - return workspace.isScrollable(); + private boolean isWorkspaceScrollable() { + Bundle result = mLauncher.getTestInfo(TestProtocol.REQUEST_DOES_WORKSPACE_HAVE_SECOND_PAGE); + return result.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, false); } @NonNull From eff177a7f25c306d6d88d1db0dde6e455052d7c4 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 23 Sep 2019 12:31:48 -0700 Subject: [PATCH 019/109] Fix wrong check for debug mode Bug: 140246642 Change-Id: I4ce7cf623fe31d53fd9f6506f339d51a64ed8f8d --- .../android/launcher3/uioverrides/DejankBinderTracker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java b/quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java index ff4c0f03d1..d8aa235823 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java +++ b/quickstep/src/com/android/launcher3/uioverrides/DejankBinderTracker.java @@ -96,8 +96,8 @@ public class DejankBinderTracker implements Binder.ProxyTransactListener { @MainThread public void startTracking() { - if (Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") - || Build.TYPE.toLowerCase(Locale.ROOT).equals("eng")) { + if (!Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") + && !Build.TYPE.toLowerCase(Locale.ROOT).equals("eng")) { Log.wtf(TAG, "Unexpected use of binder tracker in non-debug build", new Exception()); return; } From 5466699f0bb9f7a4a8cb877873cece9ed29d4393 Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 23 Sep 2019 13:57:32 -0700 Subject: [PATCH 020/109] Removing debug tracing for flakes that stopped reproing Bug: 139941530 Bug: 140311911 Change-Id: Idf4c013373e627db92aa96f9207e25336ee039f8 --- .../android/quickstep/OverviewCommandHelper.java | 3 --- .../android/launcher3/LauncherStateManager.java | 15 --------------- .../android/launcher3/testing/TestProtocol.java | 2 -- 3 files changed, 20 deletions(-) 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 14ff47b6a9..222ef97d92 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -164,9 +164,6 @@ public class OverviewCommandHelper { @Override public void run() { - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "RecentsActivityCommand.run"); - } long elapsedTime = mCreateTime - mLastToggleTime; mLastToggleTime = mCreateTime; diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index 63914b0eb5..d66e5813b9 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -227,11 +227,6 @@ public class LauncherStateManager { private void goToState(LauncherState state, boolean animated, long delay, final Runnable onCompleteRunnable) { - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "goToState: " + - state.getClass().getSimpleName() + - " @ " + Log.getStackTraceString(new Throwable())); - } animated &= Utilities.areAnimationsEnabled(mLauncher); if (mLauncher.isInState(state)) { if (mConfig.mCurrentAnimation == null) { @@ -412,11 +407,6 @@ public class LauncherStateManager { mState.onStateDisabled(mLauncher); } mState = state; - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.STABLE_STATE_MISMATCH, "onStateTransitionStart: " + - state.getClass().getSimpleName() + - " @ " + Log.getStackTraceString(new Throwable())); - } mState.onStateEnabled(mLauncher); mLauncher.onStateSet(mState); @@ -436,11 +426,6 @@ public class LauncherStateManager { if (state != mCurrentStableState) { mLastStableState = state.getHistoryForState(mCurrentStableState); mCurrentStableState = state; - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "onStateTransitionEnd: " + - state.getClass().getSimpleName() + - " @ " + Log.getStackTraceString(new Throwable())); - } } state.onStateTransitionEnd(mLauncher); diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 19c557c9ff..d286ae211c 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -84,7 +84,5 @@ public final class TestProtocol { public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824"; public static final String NO_DRAG_TO_WORKSPACE = "b/138729456"; public static final String APP_NOT_DISABLED = "b/139891609"; - public static final String ALL_APPS_UPON_RECENTS = "b/139941530"; - public static final String STABLE_STATE_MISMATCH = "b/140311911"; public static final String WELLBEING_NO_TASK_MENU = "b/141275518"; } From 10b898eee6fef17206c2007ec64f99929e22efac Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 24 Sep 2019 11:26:57 -0700 Subject: [PATCH 021/109] Fix NPE when trying to construct WorkspaceItemInfo with null intent data. We change the way we parse the install queue; so this seems to be a rare case when trying to flush an install queue from an old apk with a launcher apk with the new parsing changes. Bug: 140935140 Change-Id: I14db4c3f70ed2e1bc5ad31dec7e6473cd6f8f13c --- src/com/android/launcher3/InstallShortcutReceiver.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 670cd2877d..f19c602685 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -631,6 +631,11 @@ public class InstallShortcutReceiver extends BroadcastReceiver { } private static WorkspaceItemInfo createWorkspaceItemInfo(Intent data, LauncherAppState app) { + if (data == null) { + Log.e(TAG, "Can't construct WorkspaceItemInfo with null data"); + return null; + } + Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON); From 6096451dbf55e134d0a859b951c5a19b6951f68f Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 24 Sep 2019 11:48:58 -0700 Subject: [PATCH 022/109] Removing "Failed to get system health diags" message from fallback tests Now getting diags though the test process that has right permissions. This doesn't fix other failures in fallback tests. Bug: 141517004 Change-Id: Ibba5f0471a83525a64544c62dbe82ab3e11712cd --- .../tests/src/com/android/quickstep/FallbackRecentsTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index de762838af..986f845985 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -122,6 +122,11 @@ public class FallbackRecentsTest { } } }; + if (TestHelpers.isInLauncherProcess()) { + mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand( + TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()). + getString("result")); + } } @NavigationModeSwitch From 9b1c1682736a8d722f933322efa4a6bec2a3561c Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 24 Sep 2019 11:48:58 -0700 Subject: [PATCH 023/109] Removing "Failed to get system health diags" message from fallback tests Now getting diags though the test process that has right permissions. This doesn't fix other failures in fallback tests. Bug: 141517004 Change-Id: Ibba5f0471a83525a64544c62dbe82ab3e11712cd Merged-in: Ibba5f0471a83525a64544c62dbe82ab3e11712cd --- .../src/com/android/quickstep/FallbackRecentsTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index e5f949b880..b8c00e4344 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -42,6 +42,7 @@ import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.Until; import com.android.launcher3.tapl.LauncherInstrumentation; +import com.android.launcher3.tapl.TestHelpers; import com.android.launcher3.testcomponent.TestCommandReceiver; import com.android.launcher3.util.rule.FailureWatcher; import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; @@ -103,6 +104,11 @@ public class FallbackRecentsTest { } } }; + if (TestHelpers.isInLauncherProcess()) { + mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand( + TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()). + getString("result")); + } } @NavigationModeSwitch(mode = THREE_BUTTON) From 3944746fb6e10725cb058d9428c08aaa88eee255 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Thu, 19 Sep 2019 09:25:17 -0700 Subject: [PATCH 024/109] Fixed a bug where restored promise icons stay promise icons. Test: 1 Turn off WiFi 2 Install app. (Promise icon gets added to home screen). 3 Backup launcher. 4 Restore launcher. 5 Turn on WiFi 6 Note promise icon gets updated with as installation progresses. Will submit to future/master later. Bug: 140212732 Change-Id: I63cedc6c16f5028297fb1a0852ffbd4473319ae9 (cherry picked from commit 0e1b17f8c49c8bb149b3779e30b3cca17e2b8659) --- src/com/android/launcher3/WorkspaceItemInfo.java | 2 +- src/com/android/launcher3/model/PackageUpdatedTask.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/WorkspaceItemInfo.java b/src/com/android/launcher3/WorkspaceItemInfo.java index 1323588e32..23795c5c0e 100644 --- a/src/com/android/launcher3/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/WorkspaceItemInfo.java @@ -212,7 +212,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { public ComponentName getTargetComponent() { ComponentName cn = super.getTargetComponent(); if (cn == null && (itemType == Favorites.ITEM_TYPE_SHORTCUT - || hasStatusFlag(FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON))) { + || hasStatusFlag(FLAG_SUPPORTS_WEB_UI|FLAG_AUTOINSTALL_ICON|FLAG_RESTORED_ICON))) { // Legacy shortcuts and promise icons with web UI may not have a componentName but just // a packageName. In that case create a dummy componentName instead of adding additional // check everywhere. diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 5e6c7b8c2d..d6ebaaf106 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -55,6 +55,9 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import static com.android.launcher3.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; +import static com.android.launcher3.WorkspaceItemInfo.FLAG_RESTORED_ICON; + /** * Handles updates due to changes in package manager (app installed/updated/removed) * or when a user availability changes. @@ -221,7 +224,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { isTargetValid = LauncherAppsCompat.getInstance(context) .isActivityEnabledForProfile(cn, mUser); } - if (si.hasStatusFlag(FLAG_AUTOINSTALL_ICON)) { + if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) { if (updateWorkspaceItemIntent(context, si, packageName)) { infoUpdated = true; } else if (si.hasPromiseIconUi()) { From 4a1d9b12c5de21235287879c8c3e41d7d23d7bc3 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 19 Sep 2019 17:28:00 -0700 Subject: [PATCH 025/109] Allow LongPress between homescreen icons approach: Ignore BubbleTextView touches in padding Test: Manual Bug:141265063 Change-Id: I579d414293e922e926410d0373f101f9dde9bce0 --- src/com/android/launcher3/BubbleTextView.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index b1132494a2..4d177103d3 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -133,6 +133,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, @ViewDebug.ExportedProperty(category = "launcher") private boolean mDisableRelayout = false; + @ViewDebug.ExportedProperty(category = "launcher") + private final boolean mIgnorePaddingTouch; + private IconLoadRequest mIconLoadRequest; public BubbleTextView(Context context) { @@ -159,19 +162,25 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); setCompoundDrawablePadding(grid.iconDrawablePaddingPx); defaultIconSize = grid.iconSizePx; + mIgnorePaddingTouch = true; } else if (display == DISPLAY_ALL_APPS) { DeviceProfile grid = mActivity.getDeviceProfile(); setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx); setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx); defaultIconSize = grid.allAppsIconSizePx; + mIgnorePaddingTouch = true; } else if (display == DISPLAY_FOLDER) { DeviceProfile grid = mActivity.getDeviceProfile(); setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx); setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx); defaultIconSize = grid.folderChildIconSizePx; + mIgnorePaddingTouch = true; } else { + // widget_selection or shortcut_popup defaultIconSize = mActivity.getDeviceProfile().iconSizePx; + mIgnorePaddingTouch = false; } + mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false); mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride, @@ -319,6 +328,15 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, @Override public boolean onTouchEvent(MotionEvent event) { + // ignore events if they happen in padding area + if (event.getAction() == MotionEvent.ACTION_DOWN && mIgnorePaddingTouch + && (event.getY() < getPaddingTop() + || event.getX() < getPaddingLeft() + || event.getY() > getHeight() - getPaddingBottom() + || event.getX() > getWidth() - getPaddingRight())) { + return false; + } + // Call the superclass onTouchEvent first, because sometimes it changes the state to // isPressed() on an ACTION_UP boolean result = super.onTouchEvent(event); From 8a1ba838f4a75a19623dcaf41bf2dd581af06ac3 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 24 Sep 2019 13:58:07 -0700 Subject: [PATCH 026/109] Move offscreenTranslation calculation to LauncherRecentsView Couple of benefits here: - Doesn't rely on having a measured TaskView, since it already knows how to calculate the task size - Code can be shared (planning to use this for quick switch from home) Bug: Change-Id: I517a78506ac95fcc37d9225a074427941d691903 --- .../LauncherActivityControllerHelper.java | 12 +---------- .../quickstep/views/LauncherRecentsView.java | 21 +++++++++++++++++++ .../android/quickstep/views/RecentsView.java | 2 +- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index c17b2fe50e..c03db81861 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -273,17 +273,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe // from the side. Calculate the start translation based on current scale/scroll. float currScale = recentsView.getScaleX(); float scrollOffsetX = recentsView.getScrollOffset(); - - float offscreenX = NORMAL.getOverviewScaleAndTranslation(activity).translationX; - // The first task is hidden, so offset by its width. - int firstTaskWidth = recentsView.getTaskViewAt(0).getWidth(); - offscreenX -= (firstTaskWidth + recentsView.getPageSpacing()) * currScale; - // Offset since scale pushes tasks outwards. - offscreenX += firstTaskWidth * (currScale - 1) / 2; - offscreenX = Math.max(0, offscreenX); - if (recentsView.isRtl()) { - offscreenX = -offscreenX; - } + float offscreenX = recentsView.getOffscreenTranslationX(currScale); float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0; float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 03441c87ec..b601834f3b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -57,6 +57,8 @@ import com.android.quickstep.util.LayoutUtils; @TargetApi(Build.VERSION_CODES.O) public class LauncherRecentsView extends RecentsView implements StateListener { + private static final Rect sTempRect = new Rect(); + private final TransformParams mTransformParams = new TransformParams(); public LauncherRecentsView(Context context) { @@ -144,6 +146,25 @@ public class LauncherRecentsView extends RecentsView implements StateL LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect); } + /** + * @return The translationX to apply to this view so that the first task is just offscreen. + */ + public float getOffscreenTranslationX(float recentsScale) { + float offscreenX = NORMAL.getOverviewScaleAndTranslation(mActivity).translationX; + // Offset since scale pushes tasks outwards. + getTaskSize(sTempRect); + int taskWidth = sTempRect.width(); + offscreenX += taskWidth * (recentsScale - 1) / 2; + if (mRunningTaskTileHidden) { + // The first task is hidden, so offset by its width. + offscreenX -= (taskWidth + getPageSpacing()) * recentsScale; + } + if (isRtl()) { + offscreenX = -offscreenX; + } + return offscreenX; + } + @Override protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { 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 12b37cbd6f..554f4372c3 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 @@ -272,7 +272,7 @@ public abstract class RecentsView extends PagedView impl // Only valid until the launcher state changes to NORMAL protected int mRunningTaskId = -1; - private boolean mRunningTaskTileHidden; + protected boolean mRunningTaskTileHidden; private Task mTmpRunningTask; private boolean mRunningTaskIconScaledDown = false; From 599e95bddedf7b6efe42692d48bfe23faec5ec32 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 24 Sep 2019 13:58:32 -0700 Subject: [PATCH 027/109] Fixing some tests > Adding retry to fallback recents tests > Fixing provider test after provider name change > Fixing AllApps icon detection when there is no more scroll available Bug: 141390432 Bug: 141523101 Bug: 141517004 Bug: 141524555 Bug: 141522764 Change-Id: I425638d20c053206134835dabde819f16160f035 --- .../quickstep/FallbackRecentsTest.java | 20 ++++++++++++++----- .../ui/DefaultLayoutProviderTest.java | 4 ++-- .../com/android/launcher3/tapl/AllApps.java | 15 ++++++++------ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index 986f845985..3697230ee5 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -53,6 +53,7 @@ import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.tapl.OverviewTask; import com.android.launcher3.tapl.TestHelpers; import com.android.launcher3.testcomponent.TestCommandReceiver; +import com.android.launcher3.util.Wait; import com.android.launcher3.util.rule.FailureWatcher; import com.android.launcher3.util.rule.SimpleActivityRule; import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; @@ -147,16 +148,25 @@ public class FallbackRecentsTest { mLauncher.getBackground().switchToOverview(); } - protected void executeOnRecents(Consumer f) throws Exception { + protected void executeOnRecents(Consumer f) { getFromRecents(r -> { f.accept(r); - return null; + return true; }); } - protected T getFromRecents(Function f) throws Exception { + protected T getFromRecents(Function f) { if (!TestHelpers.isInLauncherProcess()) return null; - return MAIN_EXECUTOR.submit(() -> f.apply(mActivityMonitor.getActivity())).get(); + Object[] result = new Object[1]; + Wait.atMost("Failed to get from recents", () -> MAIN_EXECUTOR.submit(() -> { + RecentsActivity activity = mActivityMonitor.getActivity(); + if (activity == null) { + return false; + } + result[0] = f.apply(activity); + return true; + }).get(), DEFAULT_UI_TIMEOUT); + return (T) result[0]; } private BaseOverview pressHomeAndGoToOverview() { @@ -166,7 +176,7 @@ public class FallbackRecentsTest { @NavigationModeSwitch @Test - public void testOverview() throws Exception { + public void testOverview() { startAppFast(getAppPackageName()); startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); startTestActivity(2); diff --git a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java index a76b4a4886..3d4e17bf5c 100644 --- a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java +++ b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java @@ -30,7 +30,7 @@ import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.LauncherAppWidgetProviderInfo; -import com.android.launcher3.testcomponent.TestCommandReceiver; +import com.android.launcher3.testcomponent.TestCommandProvider; import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.rule.ShellCommandRule; @@ -63,7 +63,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { PackageManager pm = mTargetContext.getPackageManager(); ProviderInfo pi = pm.getProviderInfo(new ComponentName(mContext, - TestCommandReceiver.class), 0); + TestCommandProvider.class), 0); mAuthority = pi.authority; } diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 0359ff7e92..7754b5e52b 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -54,7 +54,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { } private boolean hasClickableIcon(UiObject2 allAppsContainer, UiObject2 appListRecycler, - BySelector appIconSelector, int bottomOffset) { + BySelector appIconSelector, int displayBottom) { final UiObject2 icon = appListRecycler.findObject(appIconSelector); if (icon == null) { LauncherInstrumentation.log("hasClickableIcon: icon not visible"); @@ -66,7 +66,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { LauncherInstrumentation.log("hasClickableIcon: icon center is under search box"); return false; } - if (iconBounds.bottom > bottomOffset) { + if (iconBounds.bottom > displayBottom) { LauncherInstrumentation.log("hasClickableIcon: icon center bellow bottom offset"); return false; } @@ -97,7 +97,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { int bottomGestureMargin = ResourceUtils.getNavbarSize( ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; - int bottomOffset = mLauncher.getDevice().getDisplayHeight() - bottomGestureMargin; + int deviceHeight = mLauncher.getDevice().getDisplayHeight(); + int displayBottom = deviceHeight - bottomGestureMargin; allAppsContainer.setGestureMargins( 0, getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1, @@ -105,13 +106,13 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { bottomGestureMargin); final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher); if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, - bottomOffset)) { + displayBottom)) { scrollBackToBeginning(); int attempts = 0; int scroll = getAllAppsScroll(); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) { while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, - bottomOffset)) { + displayBottom)) { mLauncher.scroll(allAppsContainer, Direction.DOWN, 0.8f, null, 50); final int newScroll = getAllAppsScroll(); if (newScroll == scroll) break; @@ -126,9 +127,11 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { verifyActiveContainer(); } + // Ignore bottom offset selection here as there might not be any scroll more scroll + // region available. mLauncher.assertTrue("Unable to scroll to a clickable icon: " + appName, hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, - bottomOffset)); + deviceHeight)); final UiObject2 appIcon = mLauncher.waitForObjectInContainer(appListRecycler, appIconSelector); From b1ee7d241e25d6ba632023816ed2f120d2cb62fb Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 24 Sep 2019 16:36:50 -0700 Subject: [PATCH 028/109] Fix FlagOverrideSampleTest Bug: 141576561 Change-Id: Id6f14dc71fec651ff35ec859598b761c8502514f --- .../launcher3/config/FlagOverrideSampleTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java index ace1420fc2..31a037b165 100644 --- a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java +++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideSampleTest.java @@ -21,13 +21,19 @@ public class FlagOverrideSampleTest { @Rule public final FlagOverrideRule flags = new FlagOverrideRule(); - @FlagOverride(key = "EXAMPLE_FLAG", value = true) + /** + * Test if flag can be overriden to true via annoation. + */ + @FlagOverride(key = "FAKE_LANDSCAPE_UI", value = true) @Test public void withFlagOn() { assertTrue(FeatureFlags.FAKE_LANDSCAPE_UI.get()); } - @FlagOverride(key = "EXAMPLE_FLAG", value = false) + /** + * Test if flag can be overriden to false via annoation. + */ + @FlagOverride(key = "FAKE_LANDSCAPE_UI", value = false) @Test public void withFlagOff() { assertFalse(FeatureFlags.FAKE_LANDSCAPE_UI.get()); From 926e29f8b6f27f86f064e016c935bed2c63d82c7 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 24 Sep 2019 16:06:24 -0700 Subject: [PATCH 029/109] Removing temporary checks that tests are running on AVD Bug: 136278866 Change-Id: I2b7b63b7745936ea84b7cba599e21d954b682ba5 --- .../com/android/quickstep/StartLauncherViaGestureTests.java | 5 ----- tests/tapl/com/android/launcher3/tapl/Workspace.java | 2 -- 2 files changed, 7 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java index c5b560c3fc..2111e2ca27 100644 --- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java +++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java @@ -25,7 +25,6 @@ import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.Launcher; -import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.util.RaceConditionReproducer; import com.android.quickstep.NavigationModeSwitchRule.Mode; import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; @@ -80,8 +79,6 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest { @Test @NavigationModeSwitch public void testStressPressHome() { - if (LauncherInstrumentation.isAvd()) return; // b/136278866 - for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) { // Destroy Launcher activity. closeLauncherActivity(); @@ -94,8 +91,6 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest { @Test @NavigationModeSwitch public void testStressSwipeToOverview() { - if (LauncherInstrumentation.isAvd()) return; // b/136278866 - for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) { // Destroy Launcher activity. closeLauncherActivity(); diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 510ea14091..da74b66f21 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -38,8 +38,6 @@ import com.android.launcher3.testing.TestProtocol; * Operations on the workspace screen. */ public final class Workspace extends Home { - private static final float FLING_SPEED = - LauncherInstrumentation.isAvd() ? 1500.0F : 3500.0F; private static final int DRAG_DURACTION = 2000; private static final int FLING_STEPS = 10; private final UiObject2 mHotseat; From 39eb7ec87783dfc473adb8e76806cd7f08074373 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 24 Sep 2019 18:13:45 -0700 Subject: [PATCH 030/109] Removing unused method isAvd Bug: 136278866 Change-Id: I06396a60e44d25cd2b532f6ce31c2ce965263817 --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 65208ceb58..b200a27a03 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -37,7 +37,6 @@ import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; @@ -239,10 +238,6 @@ public final class LauncherInstrumentation { return null; } - public static boolean isAvd() { - return Build.MODEL.contains("Cuttlefish"); - } - static void log(String message) { Log.d(TAG, message); } From 5f660f40c7998abc42c6df4b1aae5ca4cb5e1a4a Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 24 Sep 2019 18:18:35 -0700 Subject: [PATCH 031/109] Remove unused getDisplayDensity Change-Id: I4c63f4f8c0b0d8596e6b2db9839af059961157a8 --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 65208ceb58..93bf9af87b 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -845,10 +845,6 @@ public final class LauncherInstrumentation { mDevice.waitForIdle(); } - float getDisplayDensity() { - return mInstrumentation.getTargetContext().getResources().getDisplayMetrics().density; - } - int getTouchSlop() { return ViewConfiguration.get(getContext()).getScaledTouchSlop(); } From 49b64a98cad6b3b91d6550adbb1b9ea8c68e87b4 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 25 Sep 2019 11:26:56 -0700 Subject: [PATCH 032/109] Removing debug tracing for a fixed bug Bug: 141275518 Change-Id: I171361d4f797f587b404eed07108224d8ab844f8 --- .../src/com/android/quickstep/views/TaskMenuView.java | 9 --------- .../src/com/android/quickstep/views/TaskView.java | 3 --- src/com/android/launcher3/testing/TestProtocol.java | 1 - 3 files changed, 13 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java index 742d6a24ce..07d079664a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java @@ -161,9 +161,6 @@ public class TaskMenuView extends AbstractFloatingView { } public static TaskMenuView showForTask(TaskView taskView) { - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "showForTask"); - } BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext()); final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate( R.layout.task_menu, activity.getDragLayer(), false); @@ -171,15 +168,9 @@ public class TaskMenuView extends AbstractFloatingView { } private boolean populateAndShowForTask(TaskView taskView) { - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "populateAndShowForTask1"); - } if (isAttachedToWindow()) { return false; } - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "populateAndShowForTask2"); - } mActivity.getDragLayer().addView(this); mTaskView = taskView; addMenuOptions(mTaskView); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 3eed2812a1..51802dffd2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -391,9 +391,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mIconView.setDrawable(icon); mIconView.setOnClickListener(v -> showTaskMenu(Touch.TAP)); mIconView.setOnLongClickListener(v -> { - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.WELLBEING_NO_TASK_MENU, "setOnLongClickListener"); - } requestDisallowInterceptTouchEvent(true); return showTaskMenu(Touch.LONGPRESS); }); diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index d286ae211c..bb44d90a3c 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -84,5 +84,4 @@ public final class TestProtocol { public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824"; public static final String NO_DRAG_TO_WORKSPACE = "b/138729456"; public static final String APP_NOT_DISABLED = "b/139891609"; - public static final String WELLBEING_NO_TASK_MENU = "b/141275518"; } From 7ad1026cad1029ca12e95f51f8b7322617f46806 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 25 Sep 2019 13:59:37 -0700 Subject: [PATCH 033/109] Continuing experiments with test stability attribute Change-Id: I7ada0a7f4f0e0e9ca90a3d44ae88fc00d54d74df --- .../util/rule/TestStabilityRule.java | 115 ++++++++---------- 1 file changed, 49 insertions(+), 66 deletions(-) diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java index 8feadbee9e..d7f41bf041 100644 --- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java +++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java @@ -40,8 +40,8 @@ public class TestStabilityRule implements TestRule { + "(?(BuildFromAndroidStudio|" + "([0-9]+|[A-Z])-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+))|" + "(?([0-9]+|[A-Z])-P[0-9]+)|" - + "(?([0-9]+|[A-Z])+-[0-9]+|" - + "(?([0-9]+|[A-Z])+))" + + "(?([0-9]+|[A-Z])-[0-9]+)|" + + "(?[0-9]+|[A-Z])" + ")$"); private static final Pattern PLATFORM_BUILD = Pattern.compile("^(" @@ -61,70 +61,7 @@ public class TestStabilityRule implements TestRule { return new Statement() { @Override public void evaluate() throws Throwable { - final String launcherVersion = - getInstrumentation(). - getContext(). - getPackageManager(). - getPackageInfo( - UiDevice.getInstance(getInstrumentation()). - getLauncherPackageName(), - 0). - versionName; - - final Matcher launcherBuildMatcher = LAUNCHER_BUILD.matcher(launcherVersion); - - boolean launcherLocalBuild = false; - boolean launcherUnbundledPresubmit = false; - boolean launcherUnbundledPostsubmit = false; - boolean launcherPlatform = false; - - if (!launcherBuildMatcher.find()) { - Log.e(TAG, "Match not found"); - } else if (launcherBuildMatcher.group("local") != null) { - launcherLocalBuild = true; - } else if (launcherBuildMatcher.group("presubmit") != null) { - launcherUnbundledPresubmit = true; - } else if (launcherBuildMatcher.group("postsubmit") != null) { - launcherUnbundledPostsubmit = true; - } else if (launcherBuildMatcher.group("platform") != null) { - launcherPlatform = true; - } else { - Log.e(TAG, "ERROR1"); - } - - boolean platformLocalBuild = false; - boolean platformPresubmit = false; - boolean platformPostsubmit = false; - - final String platformVersion = Build.VERSION.INCREMENTAL; - final Matcher platformBuildMatcher = PLATFORM_BUILD.matcher(platformVersion); - if (!platformBuildMatcher.find()) { - Log.e(TAG, "Match not found"); - } else if (platformBuildMatcher.group("commandLine") != null) { - platformLocalBuild = true; - } else if (platformBuildMatcher.group("presubmit") != null) { - platformPresubmit = true; - } else if (platformBuildMatcher.group("postsubmit") != null) { - platformPostsubmit = true; - } else { - Log.e(TAG, "ERROR2"); - } - - Log.d(TAG, "Launcher: " + launcherVersion + ", platform: " + platformVersion); - - if (launcherLocalBuild && (platformLocalBuild || platformPostsubmit)) { - Log.d(TAG, "LOCAL RUN"); - } else if (launcherUnbundledPresubmit && platformPostsubmit) { - Log.d(TAG, "UNBUNDLED PRESUBMIT"); - } else if (launcherUnbundledPostsubmit && platformPostsubmit) { - Log.d(TAG, "UNBUNDLED POSTSUBMIT"); - } else if (launcherPlatform && platformPresubmit) { - Log.d(TAG, "PLATFORM PRESUBMIT"); - } else if (launcherPlatform && platformPostsubmit) { - Log.d(TAG, "PLATFORM POSTSUBMIT"); - } else { - Log.e(TAG, "ERROR3"); - } + getRunFlavor(); base.evaluate(); } @@ -133,4 +70,50 @@ public class TestStabilityRule implements TestRule { return base; } } + + private static void getRunFlavor() throws Exception { + final String launcherVersion = getInstrumentation(). + getContext(). + getPackageManager(). + getPackageInfo( + UiDevice.getInstance(getInstrumentation()). + getLauncherPackageName(), + 0). + versionName; + + final Matcher launcherBuildMatcher = LAUNCHER_BUILD.matcher(launcherVersion); + + if (!launcherBuildMatcher.find()) { + Log.e(TAG, "Match not found"); + } + + final String platformVersion = Build.VERSION.INCREMENTAL; + final Matcher platformBuildMatcher = PLATFORM_BUILD.matcher(platformVersion); + + if (!platformBuildMatcher.find()) { + Log.e(TAG, "Match not found"); + } + + Log.d(TAG, "Launcher: " + launcherVersion + ", platform: " + platformVersion); + + if (launcherBuildMatcher.group("local") != null && ( + platformBuildMatcher.group("commandLine") != null || + platformBuildMatcher.group("postsubmit") != null)) { + Log.d(TAG, "LOCAL RUN"); + } else if (launcherBuildMatcher.group("presubmit") != null + && platformBuildMatcher.group("postsubmit") != null) { + Log.d(TAG, "UNBUNDLED PRESUBMIT"); + } else if (launcherBuildMatcher.group("postsubmit") != null + && platformBuildMatcher.group("postsubmit") != null) { + Log.d(TAG, "UNBUNDLED POSTSUBMIT"); + } else if (launcherBuildMatcher.group("platform") != null + && platformBuildMatcher.group("presubmit") != null) { + Log.d(TAG, "PLATFORM PRESUBMIT"); + } else if (launcherBuildMatcher.group("platform") != null + && platformBuildMatcher.group("postsubmit") != null) { + Log.d(TAG, "PLATFORM POSTSUBMIT"); + } else { + Log.e(TAG, "ERROR3"); + } + } } From 59e908b54f72768efcae3db5897c50010d1fc5f2 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Mon, 26 Aug 2019 14:36:02 -0700 Subject: [PATCH 034/109] migrate custom widgets in comply with plugin framework Bug: 139888225 Change-Id: I8a3d0fe2689ad5ba24b19309728bbad0b6287f71 Merged-In: I8a3d0fe2689ad5ba24b19309728bbad0b6287f71 (cherry picked from commit c7a6c2979cc063dd493316d0d19cbc0501a23a64) --- res/values/attrs.xml | 15 -- res/xml/custom_widgets.xml | 31 --- src/com/android/launcher3/Launcher.java | 13 +- .../android/launcher3/LauncherAppState.java | 3 + .../launcher3/LauncherAppWidgetHost.java | 6 +- src/com/android/launcher3/LauncherModel.java | 4 - .../compat/AppWidgetManagerCompat.java | 13 +- .../compat/AppWidgetManagerCompatVL.java | 39 ++-- .../compat/AppWidgetManagerCompatVO.java | 4 +- .../android/launcher3/config/BaseFlags.java | 7 +- .../widget/custom/CustomWidgetManager.java | 178 ++++++++++++++++++ .../widget/custom/CustomWidgetParser.java | 142 -------------- .../systemui/plugins/CustomWidgetPlugin.java | 72 +++++++ 13 files changed, 286 insertions(+), 241 deletions(-) delete mode 100644 res/xml/custom_widgets.xml create mode 100644 src/com/android/launcher3/widget/custom/CustomWidgetManager.java delete mode 100644 src/com/android/launcher3/widget/custom/CustomWidgetParser.java create mode 100644 src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java diff --git a/res/values/attrs.xml b/res/values/attrs.xml index e76b898266..7be584e932 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -159,21 +159,6 @@ - - - - - - - - - - - - - - - diff --git a/res/xml/custom_widgets.xml b/res/xml/custom_widgets.xml deleted file mode 100644 index 4b54386501..0000000000 --- a/res/xml/custom_widgets.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index d667e8c0cc..7bb618ddfc 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -79,6 +79,7 @@ import android.view.animation.OvershootInterpolator; import android.widget.Toast; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; @@ -147,7 +148,7 @@ import com.android.launcher3.widget.WidgetAddFlowHandler; import com.android.launcher3.widget.WidgetHostViewLoader; import com.android.launcher3.widget.WidgetListRowEntry; import com.android.launcher3.widget.WidgetsFullSheet; -import com.android.launcher3.widget.custom.CustomWidgetParser; +import com.android.launcher3.widget.custom.CustomWidgetManager; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -158,9 +159,6 @@ import java.util.HashSet; import java.util.List; import java.util.function.Predicate; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - /** * Default launcher application. */ @@ -1666,10 +1664,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, } else { // In this case, we either need to start an activity to get permission to bind // the widget, or we need to start an activity to configure the widget, or both. - if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && - info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) { - appWidgetId = CustomWidgetParser.getWidgetIdForCustomProvider( - this, info.componentName); + if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET) { + appWidgetId = CustomWidgetManager.INSTANCE.get(this).getWidgetIdForCustomProvider( + info.componentName); } else { appWidgetId = getAppWidgetHost().allocateAppWidgetId(); } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index b4a2216c57..d70abc2a95 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -37,6 +37,7 @@ import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SecureSettingsObserver; +import com.android.launcher3.widget.custom.CustomWidgetManager; public class LauncherAppState { @@ -149,6 +150,8 @@ public class LauncherAppState { LauncherModel setLauncher(Launcher launcher) { getLocalProvider(mContext).setLauncherProviderChangeListener(launcher); mModel.initialize(launcher); + CustomWidgetManager.INSTANCE.get(launcher) + .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts); return mModel; } diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java index 64ec730079..1215d4321f 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -27,12 +27,12 @@ import android.content.Context; import android.content.Intent; import android.os.Handler; import android.util.SparseArray; -import android.view.LayoutInflater; import android.widget.Toast; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.widget.DeferredAppWidgetHostView; import com.android.launcher3.widget.LauncherAppWidgetHostView; +import com.android.launcher3.widget.custom.CustomWidgetManager; import java.util.ArrayList; import java.util.function.IntConsumer; @@ -193,10 +193,8 @@ public class LauncherAppWidgetHost extends AppWidgetHost { LauncherAppWidgetProviderInfo appWidget) { if (appWidget.isCustomWidget()) { LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context); - LayoutInflater inflater = (LayoutInflater) - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(appWidget.initialLayout, lahv); lahv.setAppWidget(0, appWidget); + CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv); return lahv; } else if ((mFlags & FLAG_LISTENING) == 0) { DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 14f659810a..c0cf135441 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -22,7 +22,6 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; @@ -54,8 +53,6 @@ import com.android.launcher3.model.PackageUpdatedTask; import com.android.launcher3.model.ShortcutsChangedTask; import com.android.launcher3.model.UserLockStateChangedTask; import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.util.ComponentKey; -import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.PackageUserKey; @@ -553,5 +550,4 @@ public class LauncherModel extends BroadcastReceiver public Callbacks getCallback() { return mCallbacks != null ? mCallbacks.get() : null; } - } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java index 32432561b0..fc5d11c23d 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java @@ -23,19 +23,18 @@ import android.content.Context; import android.os.Bundle; import android.os.UserHandle; +import androidx.annotation.Nullable; + import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; -import com.android.launcher3.widget.custom.CustomWidgetParser; +import com.android.launcher3.widget.custom.CustomWidgetManager; import java.util.HashMap; import java.util.List; -import androidx.annotation.Nullable; - public abstract class AppWidgetManagerCompat { private static final Object sInstanceLock = new Object(); @@ -63,11 +62,9 @@ public abstract class AppWidgetManagerCompat { } public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(int appWidgetId) { - if (FeatureFlags.ENABLE_CUSTOM_WIDGETS - && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { - return CustomWidgetParser.getWidgetProvider(mContext, appWidgetId); + if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { + return CustomWidgetManager.INSTANCE.get(mContext).getWidgetProvider(appWidgetId); } - AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId); return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java index 1065748328..c8b1f67c34 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java @@ -24,12 +24,15 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import androidx.annotation.Nullable; + import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; -import com.android.launcher3.widget.custom.CustomWidgetParser; +import com.android.launcher3.widget.custom.CustomAppWidgetProviderInfo; +import com.android.launcher3.widget.custom.CustomWidgetManager; import java.util.ArrayList; import java.util.Collections; @@ -37,8 +40,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; -import androidx.annotation.Nullable; - class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { private final UserManager mUserManager; @@ -54,14 +55,11 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { return Collections.emptyList(); } if (packageUser == null) { - ArrayList providers = new ArrayList(); + ArrayList providers = new ArrayList<>(); for (UserHandle user : mUserManager.getUserProfiles()) { providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user)); } - - if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) { - providers.addAll(CustomWidgetParser.getCustomWidgets(mContext)); - } + providers.addAll(getCustomWidgets()); return providers; } // Only get providers for the given package/user. @@ -74,9 +72,9 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { } } - if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(packageUser.mUser) + if (Process.myUserHandle().equals(packageUser.mUser) && mContext.getPackageName().equals(packageUser.mPackageName)) { - providers.addAll(CustomWidgetParser.getCustomWidgets(mContext)); + providers.addAll(getCustomWidgets()); } return providers; } @@ -87,9 +85,7 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { if (FeatureFlags.GO_DISABLE_WIDGETS) { return false; } - - if (FeatureFlags.ENABLE_CUSTOM_WIDGETS - && appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { + if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) { return true; } return mAppWidgetManager.bindAppWidgetIdIfAllowed( @@ -108,9 +104,8 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { } } - if (FeatureFlags.ENABLE_CUSTOM_WIDGETS && Process.myUserHandle().equals(user)) { - for (LauncherAppWidgetProviderInfo info : - CustomWidgetParser.getCustomWidgets(mContext)) { + if (Process.myUserHandle().equals(user)) { + for (LauncherAppWidgetProviderInfo info : getCustomWidgets()) { if (info.provider.equals(provider)) { return info; } @@ -131,13 +126,13 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { result.put(new ComponentKey(info.provider, user), info); } } - - if (FeatureFlags.ENABLE_CUSTOM_WIDGETS) { - for (LauncherAppWidgetProviderInfo info : - CustomWidgetParser.getCustomWidgets(mContext)) { - result.put(new ComponentKey(info.provider, info.getProfile()), info); - } + for (LauncherAppWidgetProviderInfo info : getCustomWidgets()) { + result.put(new ComponentKey(info.provider, info.getProfile()), info); } return result; } + + List getCustomWidgets() { + return CustomWidgetManager.INSTANCE.get(mContext).getCustomWidgets(); + } } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java index b7b0563ba6..11ec333d13 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java @@ -19,14 +19,14 @@ package com.android.launcher3.compat; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; +import androidx.annotation.Nullable; + import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.PackageUserKey; import java.util.Collections; import java.util.List; -import androidx.annotation.Nullable; - class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL { AppWidgetManagerCompatVO(Context context) { diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 9455889417..7c8fe16dfc 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -23,11 +23,11 @@ import android.content.SharedPreferences; import androidx.annotation.GuardedBy; import androidx.annotation.Keep; - import androidx.annotation.VisibleForTesting; -import com.android.launcher3.Utilities; +import com.android.launcher3.Utilities; import com.android.launcher3.uioverrides.TogglableFlag; + import java.util.ArrayList; import java.util.List; import java.util.SortedMap; @@ -74,9 +74,6 @@ public abstract class BaseFlags { //Feature flag to enable pulling down navigation shade from workspace. public static final boolean PULL_DOWN_STATUS_BAR = true; - // When true, custom widgets are loaded using CustomWidgetParser. - public static final boolean ENABLE_CUSTOM_WIDGETS = false; - // Features to control Launcher3Go behavior public static final boolean GO_DISABLE_WIDGETS = false; diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java new file mode 100644 index 0000000000..f20c83d926 --- /dev/null +++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java @@ -0,0 +1,178 @@ +/* + * 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.widget.custom; + +import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX; + +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.ComponentName; +import android.content.Context; +import android.os.Parcel; +import android.os.Process; +import android.util.SparseArray; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; +import com.android.launcher3.util.MainThreadInitializedObject; +import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.widget.LauncherAppWidgetHostView; +import com.android.systemui.plugins.CustomWidgetPlugin; +import com.android.systemui.plugins.PluginListener; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +/** + * CustomWidgetManager handles custom widgets implemented as a plugin. + */ +public class CustomWidgetManager implements PluginListener { + + public static final MainThreadInitializedObject INSTANCE = + new MainThreadInitializedObject<>(CustomWidgetManager::new); + + /** + * auto provider Id is an ever-increasing number that serves as the providerId whenever a new + * custom widget has been connected. + */ + private int mAutoProviderId = 0; + private final SparseArray mPlugins; + private final SparseArray> mContexts; + private final List mCustomWidgets; + private final SparseArray mWidgetsIdMap; + private Consumer mWidgetRefreshCallback; + + private CustomWidgetManager(Context context) { + mPlugins = new SparseArray<>(); + mContexts = new SparseArray<>(); + mCustomWidgets = new ArrayList<>(); + mWidgetsIdMap = new SparseArray<>(); + PluginManagerWrapper.INSTANCE.get(context) + .addPluginListener(this, CustomWidgetPlugin.class, true); + } + + @Override + public void onPluginConnected(CustomWidgetPlugin plugin, Context context) { + mPlugins.put(mAutoProviderId, plugin); + mContexts.put(mAutoProviderId, new WeakReference<>(context)); + List providers = AppWidgetManager.getInstance(context) + .getInstalledProvidersForProfile(Process.myUserHandle()); + if (providers.isEmpty()) return; + Parcel parcel = Parcel.obtain(); + providers.get(0).writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CustomAppWidgetProviderInfo info = newInfo(mAutoProviderId, plugin, parcel, context); + parcel.recycle(); + mCustomWidgets.add(info); + mWidgetsIdMap.put(mAutoProviderId, info.provider); + mWidgetRefreshCallback.accept(null); + mAutoProviderId++; + } + + @Override + public void onPluginDisconnected(CustomWidgetPlugin plugin) { + int providerId = findProviderId(plugin); + if (providerId == -1) return; + mPlugins.remove(providerId); + mContexts.remove(providerId); + mCustomWidgets.remove(getWidgetProvider(providerId)); + mWidgetsIdMap.remove(providerId); + } + + /** + * Inject a callback function to refresh the widgets. + */ + public void setWidgetRefreshCallback(Consumer cb) { + mWidgetRefreshCallback = cb; + } + + /** + * Callback method to inform a plugin it's corresponding widget has been created. + */ + public void onViewCreated(LauncherAppWidgetHostView view) { + CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo(); + CustomWidgetPlugin plugin = mPlugins.get(info.providerId); + WeakReference context = mContexts.get(info.providerId); + if (plugin == null) return; + plugin.onViewCreated(context == null ? null : context.get(), view); + } + + /** + * Returns the list of custom widgets. + */ + @NonNull + public List getCustomWidgets() { + return mCustomWidgets; + } + + /** + * Returns the widget id for a specific provider. + */ + public int getWidgetIdForCustomProvider(@NonNull ComponentName provider) { + int index = mWidgetsIdMap.indexOfValue(provider); + if (index >= 0) { + return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - mWidgetsIdMap.keyAt(index); + } else { + return AppWidgetManager.INVALID_APPWIDGET_ID; + } + } + + /** + * Returns the widget provider in respect to given widget id. + */ + @Nullable + public LauncherAppWidgetProviderInfo getWidgetProvider(int widgetId) { + ComponentName cn = mWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId); + for (LauncherAppWidgetProviderInfo info : mCustomWidgets) { + if (info.provider.equals(cn)) return info; + } + return null; + } + + private static CustomAppWidgetProviderInfo newInfo(int providerId, CustomWidgetPlugin plugin, + Parcel parcel, Context context) { + CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo( + parcel, false, providerId); + info.provider = new ComponentName( + context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId); + + info.label = plugin.getLabel(context); + info.resizeMode = plugin.getResizeMode(context); + + info.spanX = plugin.getSpanX(context); + info.spanY = plugin.getSpanY(context); + info.minSpanX = plugin.getMinSpanX(context); + info.minSpanY = plugin.getMinSpanY(context); + return info; + } + + private int findProviderId(CustomWidgetPlugin plugin) { + for (int i = 0; i < mPlugins.size(); i++) { + int providerId = mPlugins.keyAt(i); + if (mPlugins.get(providerId) == plugin) { + return providerId; + } + } + return -1; + } +} diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java b/src/com/android/launcher3/widget/custom/CustomWidgetParser.java deleted file mode 100644 index 00720c4496..0000000000 --- a/src/com/android/launcher3/widget/custom/CustomWidgetParser.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2017 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.widget.custom; - -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProviderInfo; -import android.content.ComponentName; -import android.content.Context; -import android.content.res.TypedArray; -import android.content.res.XmlResourceParser; -import android.os.Parcel; -import android.os.Process; -import android.util.SparseArray; -import android.util.Xml; - -import com.android.launcher3.LauncherAppWidgetInfo; -import com.android.launcher3.LauncherAppWidgetProviderInfo; -import com.android.launcher3.R; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX; - -/** - * Utility class to parse {@ink CustomAppWidgetProviderInfo} definitions from xml - */ -public class CustomWidgetParser { - - private static List sCustomWidgets; - private static SparseArray sWidgetsIdMap; - - public static List getCustomWidgets(Context context) { - if (sCustomWidgets == null) { - // Synchronization not needed as it it safe to load multiple times - parseCustomWidgets(context); - } - - return sCustomWidgets; - } - - public static int getWidgetIdForCustomProvider(Context context, ComponentName provider) { - if (sWidgetsIdMap == null) { - parseCustomWidgets(context); - } - int index = sWidgetsIdMap.indexOfValue(provider); - if (index >= 0) { - return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - sWidgetsIdMap.keyAt(index); - } else { - return AppWidgetManager.INVALID_APPWIDGET_ID; - } - } - - public static LauncherAppWidgetProviderInfo getWidgetProvider(Context context, int widgetId) { - if (sWidgetsIdMap == null || sCustomWidgets == null) { - parseCustomWidgets(context); - } - ComponentName cn = sWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId); - for (LauncherAppWidgetProviderInfo info : sCustomWidgets) { - if (info.provider.equals(cn)) { - return info; - } - } - return null; - } - - private static void parseCustomWidgets(Context context) { - ArrayList widgets = new ArrayList<>(); - SparseArray idMap = new SparseArray<>(); - - List providers = AppWidgetManager.getInstance(context) - .getInstalledProvidersForProfile(Process.myUserHandle()); - if (providers.isEmpty()) { - sCustomWidgets = widgets; - sWidgetsIdMap = idMap; - return; - } - - Parcel parcel = Parcel.obtain(); - providers.get(0).writeToParcel(parcel, 0); - - try (XmlResourceParser parser = context.getResources().getXml(R.xml.custom_widgets)) { - final int depth = parser.getDepth(); - int type; - - while (((type = parser.next()) != XmlPullParser.END_TAG || - parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { - if ((type == XmlPullParser.START_TAG) && "widget".equals(parser.getName())) { - TypedArray a = context.obtainStyledAttributes( - Xml.asAttributeSet(parser), R.styleable.CustomAppWidgetProviderInfo); - - parcel.setDataPosition(0); - CustomAppWidgetProviderInfo info = newInfo(a, parcel, context); - widgets.add(info); - a.recycle(); - - idMap.put(info.providerId, info.provider); - } - } - } catch (IOException | XmlPullParserException e) { - throw new RuntimeException(e); - } - parcel.recycle(); - sCustomWidgets = widgets; - sWidgetsIdMap = idMap; - } - - private static CustomAppWidgetProviderInfo newInfo(TypedArray a, Parcel parcel, Context context) { - int providerId = a.getInt(R.styleable.CustomAppWidgetProviderInfo_providerId, 0); - CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false, providerId); - info.provider = new ComponentName(context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId); - - info.label = a.getString(R.styleable.CustomAppWidgetProviderInfo_android_label); - info.initialLayout = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_initialLayout, 0); - info.icon = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_icon, 0); - info.previewImage = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_previewImage, 0); - info.resizeMode = a.getInt(R.styleable.CustomAppWidgetProviderInfo_android_resizeMode, 0); - - info.spanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numColumns, 1); - info.spanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numRows, 1); - info.minSpanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinColumns, 1); - info.minSpanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinRows, 1); - return info; - } -} diff --git a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java new file mode 100644 index 0000000000..47aa94b406 --- /dev/null +++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java @@ -0,0 +1,72 @@ +/* + * 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.systemui.plugins; + +import android.appwidget.AppWidgetHostView; +import android.content.Context; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +/** + * Implement this plugin interface to add a custom widget. + */ +@ProvidesInterface(action = CustomWidgetPlugin.ACTION, version = CustomWidgetPlugin.VERSION) +public interface CustomWidgetPlugin extends Plugin { + + String ACTION = "com.android.systemui.action.PLUGIN_CUSTOM_WIDGET"; + int VERSION = 1; + + /** + * The label to display to the user in the AppWidget picker. + */ + String getLabel(Context context); + + /** + * The default width of the widget when added to a host, in dp. The widget will get + * at least this width, and will often be given more, depending on the host. + */ + int getSpanX(Context context); + + /** + * The default height of the widget when added to a host, in dp. The widget will get + * at least this height, and will often be given more, depending on the host. + */ + int getSpanY(Context context); + + /** + * Minimum width (in dp) which the widget can be resized to. This field has no effect if it + * is greater than minWidth or if horizontal resizing isn't enabled. + */ + int getMinSpanX(Context context); + + /** + * Minimum height (in dp) which the widget can be resized to. This field has no effect if it + * is greater than minHeight or if vertical resizing isn't enabled. + */ + int getMinSpanY(Context context); + + /** + * The rules by which a widget can be resized. + */ + int getResizeMode(Context context); + + /** + * Notify the plugin that container of the widget has been rendered, where the custom widget + * can be attached to. + */ + void onViewCreated(Context context, AppWidgetHostView parent); +} From 90c303b6a7f7808a3ada5ee5e18e9bd137c8a0ae Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Tue, 3 Sep 2019 15:49:56 -0700 Subject: [PATCH 035/109] Add OverviewScreenshotActions plugin interface and use it in TaskView. Bug: 139828243 Change-Id: Idbefc11ef32619dd5eaaa5552088859eb2304e1e --- .../quickstep/views/TaskThumbnailView.java | 38 ++++++++++++++++- .../plugins/OverviewScreenshotActions.java | 41 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index 2e6b662bf8..5799c0164f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -39,23 +39,27 @@ import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Property; import android.view.View; +import android.view.ViewGroup; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.quickstep.util.TaskCornerRadius; +import com.android.systemui.plugins.OverviewScreenshotActions; +import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; /** * A task in the Recents view. */ -public class TaskThumbnailView extends View { +public class TaskThumbnailView extends View implements PluginListener { private final static ColorMatrix COLOR_MATRIX = new ColorMatrix(); private final static ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix(); @@ -99,6 +103,7 @@ public class TaskThumbnailView extends View { private boolean mOverlayEnabled; private boolean mRotated; + private OverviewScreenshotActions mOverviewScreenshotActionsPlugin; public TaskThumbnailView(Context context) { this(context, null); @@ -146,6 +151,10 @@ public class TaskThumbnailView extends View { mPaint.setShader(null); mOverlay.reset(); } + if (mOverviewScreenshotActionsPlugin != null) { + mOverviewScreenshotActionsPlugin + .setupActions((ViewGroup) getTaskView(), getThumbnail(), mActivity); + } updateThumbnailPaintFilter(); } @@ -210,6 +219,33 @@ public class TaskThumbnailView extends View { canvas.restore(); } + @Override + public void onPluginConnected(OverviewScreenshotActions overviewScreenshotActions, + Context context) { + mOverviewScreenshotActionsPlugin = overviewScreenshotActions; + mOverviewScreenshotActionsPlugin.setupActions(getTaskView(), getThumbnail(), mActivity); + } + + @Override + public void onPluginDisconnected(OverviewScreenshotActions plugin) { + if (mOverviewScreenshotActionsPlugin != null) { + mOverviewScreenshotActionsPlugin = null; + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()) + .addPluginListener(this, OverviewScreenshotActions.class); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(this); + } + public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) { // Don't show insets in multi window mode. return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets; diff --git a/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java b/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java new file mode 100644 index 0000000000..8d9c0f4e18 --- /dev/null +++ b/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java @@ -0,0 +1,41 @@ +/* + * 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.systemui.plugins; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.view.ViewGroup; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +/** + * Implement this interface to add action buttons for overview screenshots, e.g. share, edit etc. + */ +@ProvidesInterface( + action = OverviewScreenshotActions.ACTION, version = OverviewScreenshotActions.VERSION) +public interface OverviewScreenshotActions extends Plugin { + String ACTION = "com.android.systemui.action.PLUGIN_OVERVIEW_SCREENSHOT_ACTIONS"; + int VERSION = 1; + + /** + * Setup the actions for the screenshot, including edit, save, etc. + * @param parent The parent view to add buttons on. + * @param screenshot The screenshot we will do actions on. + * @param activity THe host activity. + */ + void setupActions(ViewGroup parent, Bitmap screenshot, Activity activity); +} From 7bd93b16393573f15dadc8df39760cee1d3a29dc Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 25 Sep 2019 18:13:23 -0700 Subject: [PATCH 036/109] Reducing usage of magic constants in TAPL's widgets Bug: 123904290 Change-Id: I5f158eb06ab5d40825cc975e798296ab06fc1f1f --- tests/tapl/com/android/launcher3/tapl/Widgets.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 7d308afb99..af7d5d7cdc 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -48,7 +48,12 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling forward in widgets")) { LauncherInstrumentation.log("Widgets.flingForward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, FLING_STEPS); + final int margin = widgetsContainer.getVisibleBounds().bottom - + mLauncher.getRealDisplaySize().y + + ResourceUtils.getNavbarSize( + ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()); + mLauncher.scroll( + widgetsContainer, Direction.DOWN, 1f, new Rect(0, 0, 0, margin), FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { verifyActiveContainer(); } From 3887500f8e550a4817208ae7426bf80f77765b4d Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 25 Sep 2019 18:31:36 -0700 Subject: [PATCH 037/109] Reducing usage of magic constants in TAPL's widgets (fling back) Bug: 123904290 Change-Id: I398ff2ebd418551e3fed825edf79398e32025859 --- tests/tapl/com/android/launcher3/tapl/Widgets.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 7d308afb99..6593bb196d 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -64,7 +64,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling backwards in widgets")) { LauncherInstrumentation.log("Widgets.flingBackward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - mLauncher.scroll(widgetsContainer, Direction.UP, 1f, MARGINS, FLING_STEPS); + mLauncher.scroll(widgetsContainer, Direction.UP, 1f, null, FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) { verifyActiveContainer(); } From cd0acdb9adb8174b88797784a81d4f21b15699a4 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 25 Sep 2019 12:50:29 -0700 Subject: [PATCH 038/109] Including wrapper code in Launcher builds Change-Id: Id34cb77ffd29f68e4f286d83840989ca0d96b9d7 --- Android.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Android.mk b/Android.mk index 985612fbfb..3d1d996dfd 100644 --- a/Android.mk +++ b/Android.mk @@ -145,7 +145,7 @@ LOCAL_USE_AAPT2 := true LOCAL_AAPT2_ONLY := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else @@ -216,7 +216,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else @@ -262,7 +262,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else From d3f6d72ebfa8f3759802d3bb26a86ac6db7b9fa4 Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Tue, 3 Sep 2019 15:49:56 -0700 Subject: [PATCH 039/109] Add OverviewScreenshotActions plugin interface and use it in TaskView. Bug: 139828243 Change-Id: Idbefc11ef32619dd5eaaa5552088859eb2304e1e Merged-In: Idbefc11ef32619dd5eaaa5552088859eb2304e1e --- .../quickstep/views/TaskThumbnailView.java | 39 +++++++++++++++++- .../plugins/OverviewScreenshotActions.java | 41 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index 7f1e8980b9..044292aa67 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -39,24 +39,28 @@ import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Property; import android.view.View; +import android.view.ViewGroup; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.quickstep.util.TaskCornerRadius; +import com.android.systemui.plugins.OverviewScreenshotActions; +import com.android.systemui.plugins.PluginListener; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; /** * A task in the Recents view. */ -public class TaskThumbnailView extends View { +public class TaskThumbnailView extends View implements PluginListener { private final static ColorMatrix COLOR_MATRIX = new ColorMatrix(); private final static ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix(); @@ -100,6 +104,7 @@ public class TaskThumbnailView extends View { private boolean mOverlayEnabled; private boolean mRotated; + private OverviewScreenshotActions mOverviewScreenshotActionsPlugin; public TaskThumbnailView(Context context) { this(context, null); @@ -147,6 +152,11 @@ public class TaskThumbnailView extends View { mPaint.setShader(null); mOverlay.reset(); } + + if (mOverviewScreenshotActionsPlugin != null) { + mOverviewScreenshotActionsPlugin + .setupActions((ViewGroup) getTaskView(), getThumbnail(), mActivity); + } updateThumbnailPaintFilter(); } @@ -211,6 +221,33 @@ public class TaskThumbnailView extends View { canvas.restore(); } + @Override + public void onPluginConnected(OverviewScreenshotActions overviewScreenshotActions, + Context context) { + mOverviewScreenshotActionsPlugin = overviewScreenshotActions; + mOverviewScreenshotActionsPlugin.setupActions(getTaskView(), getThumbnail(), mActivity); + } + + @Override + public void onPluginDisconnected(OverviewScreenshotActions plugin) { + if (mOverviewScreenshotActionsPlugin != null) { + mOverviewScreenshotActionsPlugin = null; + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()) + .addPluginListener(this, OverviewScreenshotActions.class); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener(this); + } + public RectF getInsetsToDrawInFullscreen(boolean isMultiWindowMode) { // Don't show insets in multi window mode. return isMultiWindowMode ? EMPTY_RECT_F : mClippedInsets; diff --git a/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java b/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java new file mode 100644 index 0000000000..8d9c0f4e18 --- /dev/null +++ b/src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java @@ -0,0 +1,41 @@ +/* + * 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.systemui.plugins; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.view.ViewGroup; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +/** + * Implement this interface to add action buttons for overview screenshots, e.g. share, edit etc. + */ +@ProvidesInterface( + action = OverviewScreenshotActions.ACTION, version = OverviewScreenshotActions.VERSION) +public interface OverviewScreenshotActions extends Plugin { + String ACTION = "com.android.systemui.action.PLUGIN_OVERVIEW_SCREENSHOT_ACTIONS"; + int VERSION = 1; + + /** + * Setup the actions for the screenshot, including edit, save, etc. + * @param parent The parent view to add buttons on. + * @param screenshot The screenshot we will do actions on. + * @param activity THe host activity. + */ + void setupActions(ViewGroup parent, Bitmap screenshot, Activity activity); +} From cf845f0dbf82b059495373933ba809f46e48def0 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 25 Sep 2019 09:08:16 -0700 Subject: [PATCH 040/109] Fixing some robolectric tests Bug: 131115553 Bug: 141576665 Bug: 141577881 Change-Id: Idb7e9346f57fea1d0231391477fdd11ad6b96a5c --- .../launcher3/config/FlagOverrideRule.java | 99 ++++++++----------- .../launcher3/logging/FileLogTest.java | 31 ++++-- .../model/BaseModelUpdateTaskTestCase.java | 13 ++- .../model/CacheDataUpdatedTaskTest.java | 4 - .../android/launcher3/LauncherAppState.java | 2 +- .../launcher3/config/FeatureFlags.java | 9 +- .../android/launcher3/logging/FileLog.java | 10 +- 7 files changed, 82 insertions(+), 86 deletions(-) diff --git a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java index e49c67cfe0..4bb9a53fd4 100644 --- a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java +++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java @@ -7,7 +7,6 @@ import com.android.launcher3.uioverrides.TogglableFlag; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; -import org.robolectric.RuntimeEnvironment; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; @@ -15,6 +14,10 @@ import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; /** * Test rule that makes overriding flags in Robolectric tests easier. This rule clears all flags @@ -52,68 +55,48 @@ public final class FlagOverrideRule implements TestRule { boolean value(); } - private boolean ruleInProgress; - @Override public Statement apply(Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - FeatureFlags.initialize(RuntimeEnvironment.application.getApplicationContext()); - ruleInProgress = true; - try { - clearOverrides(); - applyAnnotationOverrides(description); - base.evaluate(); - } finally { - ruleInProgress = false; - clearOverrides(); + return new MyStatement(base, description); + } + + private class MyStatement extends Statement { + + private final Statement mBase; + private final Description mDescription; + + + MyStatement(Statement base, Description description) { + mBase = base; + mDescription = description; + } + + @Override + public void evaluate() throws Throwable { + Map allFlags = FeatureFlags.getTogglableFlags().stream() + .collect(Collectors.toMap(TogglableFlag::getKey, Function.identity())); + + HashMap changedValues = new HashMap<>(); + FlagOverride[] overrides = new FlagOverride[0]; + try { + for (Annotation annotation : mDescription.getAnnotations()) { + if (annotation.annotationType() == FlagOverride.class) { + overrides = new FlagOverride[] { (FlagOverride) annotation }; + } else if (annotation.annotationType() == FlagOverrides.class) { + // Note: this branch is hit if the annotation is repeated + overrides = ((FlagOverrides) annotation).value(); + } } - } - }; - } - - 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?"); - } - flag.setForTests(newValue); - } - - private void applyAnnotationOverrides(Description description) { - for (Annotation annotation : description.getAnnotations()) { - if (annotation.annotationType() == FlagOverride.class) { - applyAnnotation((FlagOverride) annotation); - } else if (annotation.annotationType() == FlagOverrides.class) { - // Note: this branch is hit if the annotation is repeated - for (FlagOverride flagOverride : ((FlagOverrides) annotation).value()) { - applyAnnotation(flagOverride); + for (FlagOverride override : overrides) { + BaseTogglableFlag flag = allFlags.get(override.key()); + changedValues.put(flag, flag.get()); + flag.setForTests(override.value()); } + mBase.evaluate(); + } finally { + // Clear the values + changedValues.forEach(BaseTogglableFlag::setForTests); } } } - - private void applyAnnotation(FlagOverride flagOverride) { - boolean found = false; - for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) { - if (flag.getKey().equals(flagOverride.key())) { - override(flag, flagOverride.value()); - found = true; - break; - } - } - if (!found) { - throw new IllegalStateException("Flag " + flagOverride.key() + " not found"); - } - } - - /** - * Resets all flags to their default values. - */ - private void clearOverrides() { - for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) { - flag.setForTests(flag.getDefaultValue()); - } - } } diff --git a/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java b/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java index 096db57f90..410a077fe0 100644 --- a/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java +++ b/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java @@ -1,20 +1,22 @@ package com.android.launcher3.logging; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; +import org.robolectric.util.Scheduler; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Calendar; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - /** * Tests for {@link FileLog} */ @@ -22,9 +24,10 @@ import static org.junit.Assert.assertTrue; public class FileLogTest { private File mTempDir; + private boolean mTestActive; @Before - public void setUp() throws Exception { + public void setUp() { int count = 0; do { mTempDir = new File(RuntimeEnvironment.application.getCacheDir(), @@ -32,14 +35,24 @@ public class FileLogTest { } while (!mTempDir.mkdir()); FileLog.setDir(mTempDir); + + mTestActive = true; + Scheduler scheduler = Shadows.shadowOf(FileLog.getHandler().getLooper()).getScheduler(); + new Thread(() -> { + while (mTestActive) { + scheduler.advanceToLastPostedRunnable(); + } + }).start(); } @After - public void tearDown() throws Exception { + public void tearDown() { // Clear existing logs new File(mTempDir, "log-0").delete(); new File(mTempDir, "log-1").delete(); mTempDir.delete(); + + mTestActive = false; } @Test @@ -49,12 +62,12 @@ public class FileLogTest { } FileLog.print("Testing", "hoolalala"); StringWriter writer = new StringWriter(); - FileLog.flushAll(new PrintWriter(writer)); + assertTrue(FileLog.flushAll(new PrintWriter(writer))); assertTrue(writer.toString().contains("hoolalala")); FileLog.print("Testing", "abracadabra", new Exception("cat! cat!")); writer = new StringWriter(); - FileLog.flushAll(new PrintWriter(writer)); + assertTrue(FileLog.flushAll(new PrintWriter(writer))); assertTrue(writer.toString().contains("abracadabra")); // Exception is also printed assertTrue(writer.toString().contains("cat! cat!")); @@ -70,7 +83,7 @@ public class FileLogTest { } FileLog.print("Testing", "hoolalala"); StringWriter writer = new StringWriter(); - FileLog.flushAll(new PrintWriter(writer)); + assertTrue(FileLog.flushAll(new PrintWriter(writer))); assertTrue(writer.toString().contains("hoolalala")); Calendar threeDaysAgo = Calendar.getInstance(); @@ -80,7 +93,7 @@ public class FileLogTest { FileLog.print("Testing", "abracadabra", new Exception("cat! cat!")); writer = new StringWriter(); - FileLog.flushAll(new PrintWriter(writer)); + assertTrue(FileLog.flushAll(new PrintWriter(writer))); assertTrue(writer.toString().contains("abracadabra")); // Exception is also printed assertTrue(writer.toString().contains("cat! cat!")); diff --git a/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java index bc936b7b21..32eb2ec5fe 100644 --- a/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java +++ b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java @@ -15,17 +15,20 @@ import android.graphics.Color; import android.os.Process; import android.os.UserHandle; +import androidx.annotation.NonNull; + import com.android.launcher3.AppFilter; import com.android.launcher3.AppInfo; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; -import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.LauncherModel.ModelUpdateTask; import com.android.launcher3.LauncherProvider; +import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.cache.CachingLogic; +import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.TestLauncherProvider; @@ -44,8 +47,6 @@ import java.util.List; import java.util.concurrent.Executor; import java.util.function.Supplier; -import androidx.annotation.NonNull; - /** * Base class for writing tests for Model update tasks. */ @@ -79,6 +80,7 @@ public class BaseModelUpdateTaskTestCase { model = mock(LauncherModel.class); modelWriter = mock(ModelWriter.class); + LauncherAppState.INSTANCE.initializeForTesting(appState); when(appState.getModel()).thenReturn(model); when(model.getWriter(anyBoolean(), anyBoolean())).thenReturn(modelWriter); when(model.getCallback()).thenReturn(callbacks); @@ -216,5 +218,10 @@ public class BaseModelUpdateTaskTestCase { public Bitmap newIcon() { return Bitmap.createBitmap(1, 1, Config.ARGB_8888); } + + @Override + public synchronized BitmapInfo getDefaultIcon(UserHandle user) { + return BitmapInfo.fromBitmap(newIcon()); + } } } diff --git a/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java index 42848f4610..81b90431a0 100644 --- a/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java @@ -11,7 +11,6 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.WorkspaceItemInfo; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -41,7 +40,6 @@ public class CacheDataUpdatedTaskTest extends BaseModelUpdateTaskTestCase { } @Test - @Ignore("This test fails with resource errors") // b/131115553 public void testCacheUpdate_update_apps() throws Exception { // Clear all icons from apps list so that its easy to check what was updated for (AppInfo info : allAppsList.data) { @@ -66,7 +64,6 @@ public class CacheDataUpdatedTaskTest extends BaseModelUpdateTaskTestCase { } @Test - @Ignore("This test fails with resource errors") // b/131115553 public void testSessionUpdate_ignores_normal_apps() throws Exception { executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app1")); @@ -75,7 +72,6 @@ public class CacheDataUpdatedTaskTest extends BaseModelUpdateTaskTestCase { } @Test - @Ignore("This test fails with resource errors") // b/131115553 public void testSessionUpdate_updates_pending_apps() throws Exception { executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app3")); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index d70abc2a95..db94bdb8c4 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -44,7 +44,7 @@ public class LauncherAppState { public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher"; // We do not need any synchronization for this variable as its only written on UI thread. - private static final MainThreadInitializedObject INSTANCE = + public static final MainThreadInitializedObject INSTANCE = new MainThreadInitializedObject<>(LauncherAppState::new); private final Context mContext; diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index e6eced1279..c502dd7af1 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -238,14 +238,7 @@ public final class FeatureFlags { @Override public int hashCode() { - int h$ = 1; - h$ *= 1000003; - h$ ^= key.hashCode(); - h$ *= 1000003; - h$ ^= getDefaultValue() ? 1231 : 1237; - h$ *= 1000003; - h$ ^= description.hashCode(); - return h$; + return key.hashCode(); } } } diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java index 923a89b1cc..04cf20ab0d 100644 --- a/src/com/android/launcher3/logging/FileLog.java +++ b/src/com/android/launcher3/logging/FileLog.java @@ -8,6 +8,8 @@ import android.os.Message; import android.util.Log; import android.util.Pair; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.util.IOUtils; import java.io.BufferedReader; @@ -88,7 +90,8 @@ public final class FileLog { Message.obtain(getHandler(), LogWriterCallback.MSG_WRITE, out).sendToTarget(); } - private static Handler getHandler() { + @VisibleForTesting + static Handler getHandler() { synchronized (DATE_FORMAT) { if (sHandler == null) { sHandler = new Handler(createAndStartNewLooper("file-logger"), @@ -102,15 +105,16 @@ public final class FileLog { * Blocks until all the pending logs are written to the disk * @param out if not null, all the persisted logs are copied to the writer. */ - public static void flushAll(PrintWriter out) throws InterruptedException { + public static boolean flushAll(PrintWriter out) throws InterruptedException { if (!ENABLED) { - return; + return false; } CountDownLatch latch = new CountDownLatch(1); Message.obtain(getHandler(), LogWriterCallback.MSG_FLUSH, Pair.create(out, latch)).sendToTarget(); latch.await(2, TimeUnit.SECONDS); + return latch.getCount() == 0; } /** From 784948235473e77e32e045f799ee7208ea4e65ea Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 25 Sep 2019 16:59:49 -0700 Subject: [PATCH 041/109] Include following chagnes to custom widget plugin 1. removed unsupported methods 2. auto-generate providerId 3. piggy-back context for the plugin to resolve resources Bug: 139888225 Change-Id: If5014099eb80efd64025230037aae3d6079b69a0 --- .../widget/custom/CustomWidgetManager.java | 45 +++++++++++-------- .../systemui/plugins/CustomWidgetPlugin.java | 17 ------- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java index cf3e26d03d..b3569f23b0 100644 --- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java +++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java @@ -50,13 +50,18 @@ public class CustomWidgetManager implements PluginListener { public static final MainThreadInitializedObject INSTANCE = new MainThreadInitializedObject<>(CustomWidgetManager::new); - private final List mPlugins; + /** + * auto provider Id is an ever-increasing number that serves as the providerId whenever a new + * custom widget has been connected. + */ + private int mAutoProviderId = 0; + private final SparseArray mPlugins; private final List mCustomWidgets; private final SparseArray mWidgetsIdMap; private Consumer mWidgetRefreshCallback; private CustomWidgetManager(Context context) { - mPlugins = new ArrayList<>(); + mPlugins = new SparseArray<>(); mCustomWidgets = new ArrayList<>(); mWidgetsIdMap = new SparseArray<>(); PluginManagerWrapper.INSTANCE.get(context) @@ -65,25 +70,28 @@ public class CustomWidgetManager implements PluginListener { @Override public void onPluginConnected(CustomWidgetPlugin plugin, Context context) { - mPlugins.add(plugin); + mPlugins.put(mAutoProviderId, plugin); List providers = AppWidgetManager.getInstance(context) .getInstalledProvidersForProfile(Process.myUserHandle()); if (providers.isEmpty()) return; Parcel parcel = Parcel.obtain(); providers.get(0).writeToParcel(parcel, 0); parcel.setDataPosition(0); - CustomAppWidgetProviderInfo info = newInfo(plugin, parcel, context); + CustomAppWidgetProviderInfo info = newInfo(mAutoProviderId, plugin, parcel, context); parcel.recycle(); mCustomWidgets.add(info); - mWidgetsIdMap.put(plugin.getProviderId(), info.provider); + mWidgetsIdMap.put(mAutoProviderId, info.provider); mWidgetRefreshCallback.accept(null); + mAutoProviderId++; } @Override public void onPluginDisconnected(CustomWidgetPlugin plugin) { - mPlugins.remove(plugin); - mCustomWidgets.remove(getWidgetProvider(plugin.getProviderId())); - mWidgetsIdMap.remove(plugin.getProviderId()); + int providerId = findProviderId(plugin); + if (providerId == -1) return; + mPlugins.remove(providerId); + mCustomWidgets.remove(getWidgetProvider(providerId)); + mWidgetsIdMap.remove(providerId); } /** @@ -98,7 +106,7 @@ public class CustomWidgetManager implements PluginListener { */ public void onViewCreated(LauncherAppWidgetHostView view) { CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo(); - CustomWidgetPlugin plugin = findPlugin(info.providerId); + CustomWidgetPlugin plugin = mPlugins.get(info.providerId); if (plugin == null) return; plugin.onViewCreated(view); } @@ -135,17 +143,14 @@ public class CustomWidgetManager implements PluginListener { return null; } - private static CustomAppWidgetProviderInfo newInfo( - CustomWidgetPlugin plugin, Parcel parcel, Context context) { - int providerId = plugin.getProviderId(); + private static CustomAppWidgetProviderInfo newInfo(int providerId, CustomWidgetPlugin plugin, + Parcel parcel, Context context) { CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo( parcel, false, providerId); info.provider = new ComponentName( context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId); info.label = plugin.getLabel(); - info.icon = plugin.getIcon(); - info.previewImage = plugin.getPreviewImage(); info.resizeMode = plugin.getResizeMode(); info.spanX = plugin.getSpanX(); @@ -155,9 +160,13 @@ public class CustomWidgetManager implements PluginListener { return info; } - @Nullable - private CustomWidgetPlugin findPlugin(int providerId) { - return mPlugins.stream().filter((p) -> p.getProviderId() == providerId).findFirst() - .orElse(null); + private int findProviderId(CustomWidgetPlugin plugin) { + for (int i = 0; i < mPlugins.size(); i++) { + int providerId = mPlugins.keyAt(i); + if (mPlugins.get(providerId) == plugin) { + return providerId; + } + } + return -1; } } diff --git a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java index 77ad7ea30a..56ebcc5dc6 100644 --- a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java +++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java @@ -29,28 +29,11 @@ public interface CustomWidgetPlugin extends Plugin { String ACTION = "com.android.systemui.action.PLUGIN_CUSTOM_WIDGET"; int VERSION = 1; - /** - * An unique identifier for this widget. Must be a non-negative integer. - */ - int getProviderId(); - /** * The label to display to the user in the AppWidget picker. */ String getLabel(); - /** - * A preview of what the AppWidget will look like after it's configured. - * If not supplied, the AppWidget's icon will be used. - */ - int getPreviewImage(); - - /** - * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the - * xml, the application icon will be used. - */ - int getIcon(); - /** * The default width of the widget when added to a host, in dp. The widget will get * at least this width, and will often be given more, depending on the host. From 45812a9ed6b75427b3076907bc8717472cd238b2 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Wed, 25 Sep 2019 13:30:55 -0700 Subject: [PATCH 042/109] Drag and drop preview size for BubbleTextView Test:Manual Bug:141260670,141263002 Change-Id: If08dba28cce3ae07bb39ddad3743dd5eea92cb90 --- src/com/android/launcher3/Workspace.java | 2 +- src/com/android/launcher3/dragndrop/DragLayer.java | 3 ++- .../android/launcher3/graphics/DragPreviewProvider.java | 7 +++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 1cb15db98e..223cd7d89d 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1493,7 +1493,7 @@ public class Workspace extends PagedView Rect dragRect = null; if (child instanceof BubbleTextView) { dragRect = new Rect(); - ((BubbleTextView) child).getIconBounds(dragRect); + BubbleTextView.getIconBounds(child, dragRect, grid.iconSizePx); dragLayerY += dragRect.top; // Note: The dragRect is used to calculate drag layer offsets, but the // dragVisualizeOffset in addition to the dragRect (the size) to position the outline. diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index b59164ae0a..cdc70611dd 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -284,7 +284,8 @@ public class DragLayer extends BaseDragLayer { // The child may be scaled (always about the center of the view) so to account for it, // we have to offset the position by the scaled size. Once we do that, we can center // the drag view about the scaled child view. - toY += Math.round(toScale * tv.getPaddingTop()); + // padding will remain constant (does not scale with size) + toY += tv.getPaddingTop(); toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2; if (dragView.getDragVisualizeOffset() != null) { toY -= Math.round(toScale * dragView.getDragVisualizeOffset().y); diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index 747efe3075..f579451971 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -195,15 +195,22 @@ public class DragPreviewProvider { private final Bitmap mPreviewSnapshot; private final Context mContext; + private final boolean mIsIcon; OutlineGeneratorCallback(Bitmap preview) { mPreviewSnapshot = preview; mContext = mView.getContext(); + mIsIcon = mView instanceof BubbleTextView; } @Override public void run() { Bitmap preview = convertPreviewToAlphaBitmap(mPreviewSnapshot); + if (mIsIcon) { + int size = Launcher.getLauncher(mContext).getDeviceProfile().iconSizePx; + preview = Bitmap.createScaledBitmap(preview, size, size, false); + } + //else case covers AppWidgetHost (doesn't drag/drop across different device profiles) // We start by removing most of the alpha channel so as to ignore shadows, and // other types of partial transparency when defining the shape of the object From 46f3999fb3edf447868ec806bfba433e8797ca11 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 26 Sep 2019 12:30:25 -0700 Subject: [PATCH 043/109] Avoiding swiping down from the from the extended touchable region around the notch in Widgets Bug: 141697444 Change-Id: I8edd6a05e34c8a7e91dab1757938d40efffb766f --- tests/tapl/com/android/launcher3/tapl/Widgets.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 2a04d46cb1..54f730e258 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -69,7 +69,12 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling backwards in widgets")) { LauncherInstrumentation.log("Widgets.flingBackward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - mLauncher.scroll(widgetsContainer, Direction.UP, 1f, null, FLING_STEPS); + mLauncher.scroll( + widgetsContainer, + Direction.UP, + 1f, + new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0), + FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) { verifyActiveContainer(); } From aca7e6da5b46bb02b08bf54fb5f62e61a3b21bf6 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 25 Sep 2019 18:13:23 -0700 Subject: [PATCH 044/109] Removing magic constants from TAPL/Widgets Bug: 123904290 Change-Id: I8abc6cde6be8a51b38782f5c94749fe0c33384c1 --- .../ui/widget/AddConfigWidgetTest.java | 6 +- .../launcher3/ui/widget/AddWidgetTest.java | 5 +- .../com/android/launcher3/tapl/Widgets.java | 64 +++++++++++++------ 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java index 3f35a3a73a..e1b3edeb5a 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java @@ -41,7 +41,6 @@ import com.android.launcher3.util.Wait; import com.android.launcher3.util.rule.ShellCommandRule; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -53,7 +52,8 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class AddConfigWidgetTest extends AbstractLauncherUiTest { - @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); + @Rule + public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); private LauncherAppWidgetProviderInfo mWidgetInfo; private AppWidgetManager mAppWidgetManager; @@ -70,14 +70,12 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest { @Test @PortraitLandscape - @org.junit.Ignore public void testWidgetConfig() throws Throwable { runTest(true); } @Test @PortraitLandscape - @org.junit.Ignore public void testConfigCancelled() throws Throwable { runTest(false); } diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java index 1edce22ec6..b8ca5ded38 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java @@ -30,7 +30,6 @@ import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TestViewHelpers; import com.android.launcher3.util.rule.ShellCommandRule; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,11 +41,11 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class AddWidgetTest extends AbstractLauncherUiTest { - @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); + @Rule + public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); @Test @PortraitLandscape - @org.junit.Ignore public void testDragIcon() throws Throwable { clearHomescreen(); mDevice.pressHome(); diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 2a04d46cb1..0cd6c385f2 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -16,8 +16,6 @@ package com.android.launcher3.tapl; -import static org.junit.Assert.fail; - import android.graphics.Point; import android.graphics.Rect; @@ -28,11 +26,13 @@ import androidx.test.uiautomator.UiObject2; import com.android.launcher3.ResourceUtils; +import java.util.Collection; +import java.util.Collections; + /** * All widgets container. */ public final class Widgets extends LauncherInstrumentation.VisibleContainer { - private static final Rect MARGINS = new Rect(100, 100, 100, 100); private static final int FLING_STEPS = 10; Widgets(LauncherInstrumentation launcher) { @@ -48,12 +48,12 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling forward in widgets")) { LauncherInstrumentation.log("Widgets.flingForward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - final int margin = widgetsContainer.getVisibleBounds().bottom - - mLauncher.getRealDisplaySize().y + - ResourceUtils.getNavbarSize( - ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()); mLauncher.scroll( - widgetsContainer, Direction.DOWN, 1f, new Rect(0, 0, 0, margin), FLING_STEPS); + widgetsContainer, + Direction.DOWN, + 1f, + new Rect(0, 0, 0, getBottomGestureMargin(widgetsContainer)), + FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { verifyActiveContainer(); } @@ -61,6 +61,16 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { } } + private int getBottomGestureMargin(UiObject2 widgetsContainer) { + return widgetsContainer.getVisibleBounds().bottom - mLauncher.getRealDisplaySize().y + + getBottomGestureSize(); + } + + private int getBottomGestureSize() { + return ResourceUtils.getNavbarSize( + ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; + } + /** * Flings backward (up) and waits the fling's end. */ @@ -83,32 +93,48 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { } public Widget getWidget(String labelText) { - final int margin = ResourceUtils.getNavbarSize( - ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; final UiObject2 widgetsContainer = verifyActiveContainer(); - widgetsContainer.setGestureMargins(0, 0, 0, margin); - final Point displaySize = mLauncher.getRealDisplaySize(); + final BySelector labelSelector = By.clazz("android.widget.TextView").text(labelText); int i = 0; - final BySelector selector = By.clazz("android.widget.TextView").text(labelText); - for (; ; ) { - final UiObject2 label = mLauncher.tryWaitForLauncherObject(selector, 300); - if (label != null) { + final Collection cells = mLauncher.getObjectsInContainer( + widgetsContainer, "widgets_cell_list_container"); + mLauncher.assertTrue("Widgets doesn't have 2 rows", cells.size() >= 2); + for (UiObject2 cell : cells) { + final UiObject2 label = cell.findObject(labelSelector); + if (label == null) continue; + final UiObject2 widget = label.getParent().getParent(); mLauncher.assertEquals( "View is not WidgetCell", "com.android.launcher3.widget.WidgetCell", widget.getClassName()); - if (widget.getVisibleBounds().bottom <= displaySize.y - margin) { + if (widget.getVisibleBounds().bottom <= displaySize.y - getBottomGestureSize()) { return new Widget(mLauncher, widget); } } - if (++i > 40) fail("Too many attempts"); - mLauncher.scroll(widgetsContainer, Direction.DOWN, 0.7f, MARGINS, 50); + mLauncher.assertTrue("Too many attempts", ++i <= 40); + final UiObject2 lowestCell = Collections.max(cells, (c1, c2) -> + Integer.compare(c1.getVisibleBounds().top, c2.getVisibleBounds().top)); + + final int gestureStart = lowestCell.getVisibleBounds().top + mLauncher.getTouchSlop(); + final int distance = gestureStart - widgetsContainer.getVisibleBounds().top; + final int bottomMargin = widgetsContainer.getVisibleBounds().height() - distance; + + mLauncher.scroll( + widgetsContainer, + Direction.DOWN, + 1f, + new Rect( + 0, + 0, + 0, + Math.max(bottomMargin, getBottomGestureMargin(widgetsContainer))), + 150); } } } From 0316d6cd7a911b8714ae151d96c537f5e3c2d3c1 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 26 Sep 2019 16:30:42 -0700 Subject: [PATCH 045/109] Fix ScrimView caret alignment and ignore touches Test:Manual Bug:79868152 Change-Id: Idd5a2b965173b8071697b50aac8760b0d84e469f --- quickstep/src/com/android/quickstep/views/ShelfScrimView.java | 2 +- src/com/android/launcher3/views/ScrimView.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java index dc6b56eecf..26e9eaf01e 100644 --- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java +++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java @@ -161,7 +161,7 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis mMidProgress = OVERVIEW.getVerticalProgress(mLauncher); Rect hotseatPadding = dp.getHotseatLayoutPadding(); int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom - - hotseatPadding.bottom - hotseatPadding.top; + + hotseatPadding.bottom + hotseatPadding.top; float dragHandleTop = Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(context, dp)); mDragHandleProgress = 1 - (dragHandleTop / mShiftRange); diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java index da1df3f899..9f59d78217 100644 --- a/src/com/android/launcher3/views/ScrimView.java +++ b/src/com/android/launcher3/views/ScrimView.java @@ -288,6 +288,7 @@ public class ScrimView extends View implements Insettable, OnChangeListener, anim.addUpdateListener((v) -> invalidate(invalidateRegion)); getOverlay().add(drawable); anim.start(); + return true; } return value; } From 22c4b3c91d5e3c24c3a7491356312c2acc57b726 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 26 Sep 2019 14:17:44 -0700 Subject: [PATCH 046/109] Removing magic constant 0.8f from AllApps Bug: 123904290 Change-Id: I91ff4d4f962eefea787989362c32d987f546e84d --- .../com/android/launcher3/tapl/AllApps.java | 7 +++- .../tapl/LauncherInstrumentation.java | 33 +++++++++++++++++ .../com/android/launcher3/tapl/Widgets.java | 36 +++---------------- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 7754b5e52b..f736078974 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -94,6 +94,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view"); + final UiObject2 searchBox = getSearchBox(allAppsContainer); int bottomGestureMargin = ResourceUtils.getNavbarSize( ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; @@ -113,7 +114,11 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) { while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, displayBottom)) { - mLauncher.scroll(allAppsContainer, Direction.DOWN, 0.8f, null, 50); + mLauncher.scrollToLastVisibleRow( + allAppsContainer, + mLauncher.getObjectsInContainer(allAppsContainer, "icon"), + searchBox.getVisibleBounds().bottom + - allAppsContainer.getVisibleBounds().top); final int newScroll = getAllAppsScroll(); if (newScroll == scroll) break; diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index dd2f4f0767..6d06d56bd1 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -59,6 +59,7 @@ import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.UiObject2; import androidx.test.uiautomator.Until; +import com.android.launcher3.ResourceUtils; import com.android.launcher3.testing.TestProtocol; import com.android.systemui.shared.system.QuickStepContract; @@ -67,6 +68,8 @@ import org.junit.Assert; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.Collections; import java.util.Deque; import java.util.LinkedList; import java.util.List; @@ -756,6 +759,36 @@ public final class LauncherInstrumentation { TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD))); } + int getBottomGestureSize() { + return ResourceUtils.getNavbarSize( + ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources()) + 1; + } + + int getBottomGestureMargin(UiObject2 container) { + return container.getVisibleBounds().bottom - getRealDisplaySize().y + + getBottomGestureSize(); + } + + void scrollToLastVisibleRow(UiObject2 container, Collection items, int topPadding) { + final UiObject2 lowestItem = Collections.max(items, (i1, i2) -> + Integer.compare(i1.getVisibleBounds().top, i2.getVisibleBounds().top)); + + final int gestureStart = lowestItem.getVisibleBounds().top + getTouchSlop(); + final int distance = gestureStart - container.getVisibleBounds().top - topPadding; + final int bottomMargin = container.getVisibleBounds().height() - distance; + + scroll( + container, + Direction.DOWN, + 1f, + new Rect( + 0, + 0, + 0, + Math.max(bottomMargin, getBottomGestureMargin(container))), + 150); + } + void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) { final Rect rect = container.getVisibleBounds(); if (margins != null) { diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 39cb0bf7ab..db20d35841 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -24,10 +24,7 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.Direction; import androidx.test.uiautomator.UiObject2; -import com.android.launcher3.ResourceUtils; - import java.util.Collection; -import java.util.Collections; /** * All widgets container. @@ -52,7 +49,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { widgetsContainer, Direction.DOWN, 1f, - new Rect(0, 0, 0, getBottomGestureMargin(widgetsContainer)), + new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer)), FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { verifyActiveContainer(); @@ -61,16 +58,6 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { } } - private int getBottomGestureMargin(UiObject2 widgetsContainer) { - return widgetsContainer.getVisibleBounds().bottom - mLauncher.getRealDisplaySize().y + - getBottomGestureSize(); - } - - private int getBottomGestureSize() { - return ResourceUtils.getNavbarSize( - ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; - } - /** * Flings backward (up) and waits the fling's end. */ @@ -117,29 +104,14 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "com.android.launcher3.widget.WidgetCell", widget.getClassName()); - if (widget.getVisibleBounds().bottom <= displaySize.y - getBottomGestureSize()) { + if (widget.getVisibleBounds().bottom + <= displaySize.y - mLauncher.getBottomGestureSize()) { return new Widget(mLauncher, widget); } } mLauncher.assertTrue("Too many attempts", ++i <= 40); - final UiObject2 lowestCell = Collections.max(cells, (c1, c2) -> - Integer.compare(c1.getVisibleBounds().top, c2.getVisibleBounds().top)); - - final int gestureStart = lowestCell.getVisibleBounds().top + mLauncher.getTouchSlop(); - final int distance = gestureStart - widgetsContainer.getVisibleBounds().top; - final int bottomMargin = widgetsContainer.getVisibleBounds().height() - distance; - - mLauncher.scroll( - widgetsContainer, - Direction.DOWN, - 1f, - new Rect( - 0, - 0, - 0, - Math.max(bottomMargin, getBottomGestureMargin(widgetsContainer))), - 150); + mLauncher.scrollToLastVisibleRow(widgetsContainer, cells, 0); } } } From 7028b10c547445f0ea05ce395edc54944e93a6a7 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 26 Sep 2019 14:17:44 -0700 Subject: [PATCH 047/109] Removing magic constant 0.8f from AllApps Bug: 123904290 Change-Id: I52aeb3c0452175ba37b2524d632e8069ba0911c9 Merged-in: I91ff4d4f962eefea787989362c32d987f546e84d --- .../com/android/launcher3/tapl/AllApps.java | 7 +++- .../tapl/LauncherInstrumentation.java | 33 +++++++++++++++++ .../com/android/launcher3/tapl/Widgets.java | 36 +++---------------- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index f070280ea2..f63612dd1f 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -90,6 +90,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view"); + final UiObject2 searchBox = getSearchBox(allAppsContainer); allAppsContainer.setGestureMargins( 0, getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1, @@ -103,7 +104,11 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { int scroll = getScroll(allAppsContainer); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) { while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) { - mLauncher.scroll(allAppsContainer, Direction.DOWN, 0.8f, null, 50); + mLauncher.scrollToLastVisibleRow( + allAppsContainer, + mLauncher.getObjectsInContainer(allAppsContainer, "icon"), + searchBox.getVisibleBounds().bottom - + allAppsContainer.getVisibleBounds().top); final int newScroll = getScroll(allAppsContainer); if (newScroll == scroll) break; diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 306fe4870e..1c8f92e917 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -59,6 +59,7 @@ import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.UiObject2; import androidx.test.uiautomator.Until; +import com.android.launcher3.ResourceUtils; import com.android.launcher3.testing.TestProtocol; import com.android.systemui.shared.system.QuickStepContract; @@ -67,6 +68,8 @@ import org.junit.Assert; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.Collections; import java.util.Deque; import java.util.LinkedList; import java.util.List; @@ -765,6 +768,36 @@ public final class LauncherInstrumentation { TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD))); } + int getBottomGestureSize() { + return ResourceUtils.getNavbarSize( + ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources()) + 1; + } + + int getBottomGestureMargin(UiObject2 container) { + return container.getVisibleBounds().bottom - getRealDisplaySize().y + + getBottomGestureSize(); + } + + void scrollToLastVisibleRow(UiObject2 container, Collection items, int topPadding) { + final UiObject2 lowestItem = Collections.max(items, (i1, i2) -> + Integer.compare(i1.getVisibleBounds().top, i2.getVisibleBounds().top)); + + final int gestureStart = lowestItem.getVisibleBounds().top + getTouchSlop(); + final int distance = gestureStart - container.getVisibleBounds().top - topPadding; + final int bottomMargin = container.getVisibleBounds().height() - distance; + + scroll( + container, + Direction.DOWN, + 1f, + new Rect( + 0, + 0, + 0, + Math.max(bottomMargin, getBottomGestureMargin(container))), + 150); + } + void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) { final Rect rect = container.getVisibleBounds(); if (margins != null) { diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 39cb0bf7ab..aabcac282b 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -24,10 +24,7 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.Direction; import androidx.test.uiautomator.UiObject2; -import com.android.launcher3.ResourceUtils; - import java.util.Collection; -import java.util.Collections; /** * All widgets container. @@ -52,7 +49,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { widgetsContainer, Direction.DOWN, 1f, - new Rect(0, 0, 0, getBottomGestureMargin(widgetsContainer)), + new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer)), FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { verifyActiveContainer(); @@ -61,16 +58,6 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { } } - private int getBottomGestureMargin(UiObject2 widgetsContainer) { - return widgetsContainer.getVisibleBounds().bottom - mLauncher.getRealDisplaySize().y + - getBottomGestureSize(); - } - - private int getBottomGestureSize() { - return ResourceUtils.getNavbarSize( - ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; - } - /** * Flings backward (up) and waits the fling's end. */ @@ -117,29 +104,14 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "com.android.launcher3.widget.WidgetCell", widget.getClassName()); - if (widget.getVisibleBounds().bottom <= displaySize.y - getBottomGestureSize()) { + if (widget.getVisibleBounds().bottom <= + displaySize.y - mLauncher.getBottomGestureSize()) { return new Widget(mLauncher, widget); } } mLauncher.assertTrue("Too many attempts", ++i <= 40); - final UiObject2 lowestCell = Collections.max(cells, (c1, c2) -> - Integer.compare(c1.getVisibleBounds().top, c2.getVisibleBounds().top)); - - final int gestureStart = lowestCell.getVisibleBounds().top + mLauncher.getTouchSlop(); - final int distance = gestureStart - widgetsContainer.getVisibleBounds().top; - final int bottomMargin = widgetsContainer.getVisibleBounds().height() - distance; - - mLauncher.scroll( - widgetsContainer, - Direction.DOWN, - 1f, - new Rect( - 0, - 0, - 0, - Math.max(bottomMargin, getBottomGestureMargin(widgetsContainer))), - 150); + mLauncher.scrollToLastVisibleRow(widgetsContainer, cells, 0); } } } From 83b03b08de944510917e6ee1ebdbea631d5fb4d4 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 26 Sep 2019 17:52:32 -0700 Subject: [PATCH 048/109] Removing a 'percent' parameter for scroll It's an invitation to use magic constants. Bug: 123904290 Change-Id: I485abbbb868c41949dddd6e2c4cf363cc44a5ccd --- tests/tapl/com/android/launcher3/tapl/AllApps.java | 6 +++--- .../tapl/com/android/launcher3/tapl/BaseOverview.java | 4 ++-- .../launcher3/tapl/LauncherInstrumentation.java | 11 +++++------ tests/tapl/com/android/launcher3/tapl/Widgets.java | 2 -- tests/tapl/com/android/launcher3/tapl/Workspace.java | 4 ++-- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index f63612dd1f..6dced8c8cd 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -150,7 +150,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS, ++attempts <= MAX_SCROLL_ATTEMPTS); - mLauncher.scroll(allAppsContainer, Direction.UP, 1, margins, 50); + mLauncher.scroll(allAppsContainer, Direction.UP, margins, 50); } try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) { @@ -177,7 +177,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); // Start the gesture in the center to avoid starting at elements near the top. mLauncher.scroll( - allAppsContainer, Direction.DOWN, 1, new Rect(0, 0, 0, mHeight / 2), 10); + allAppsContainer, Direction.DOWN, new Rect(0, 0, 0, mHeight / 2), 10); verifyActiveContainer(); } } @@ -191,7 +191,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); // Start the gesture in the center, for symmetry with forward. mLauncher.scroll( - allAppsContainer, Direction.UP, 1, new Rect(0, mHeight / 2, 0, 0), 10); + allAppsContainer, Direction.UP, new Rect(0, mHeight / 2, 0, 0), 10); verifyActiveContainer(); } } diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index 25e6e8c8f7..49c0c89088 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -55,7 +55,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { final int leftMargin = mLauncher.getTestInfo( TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN). getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); - mLauncher.scroll(overview, Direction.LEFT, 1, new Rect(leftMargin, 0, 0, 0), 20); + mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin, 0, 0, 0), 20); verifyActiveContainer(); } } @@ -93,7 +93,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { final int rightMargin = mLauncher.getTestInfo( TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN). getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); - mLauncher.scroll(overview, Direction.RIGHT, 1, new Rect(0, 0, rightMargin, 0), 20); + mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin, 0), 20); verifyActiveContainer(); } } diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 1c8f92e917..98a7a36d5d 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -789,7 +789,6 @@ public final class LauncherInstrumentation { scroll( container, Direction.DOWN, - 1f, new Rect( 0, 0, @@ -798,7 +797,7 @@ public final class LauncherInstrumentation { 150); } - void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) { + void scroll(UiObject2 container, Direction direction, Rect margins, int steps) { final Rect rect = container.getVisibleBounds(); if (margins != null) { rect.left += margins.left; @@ -816,7 +815,7 @@ public final class LauncherInstrumentation { case UP: { startX = endX = rect.centerX(); final int vertCenter = rect.centerY(); - final float halfGestureHeight = rect.height() * percent / 2.0f; + final float halfGestureHeight = rect.height() / 2.0f; startY = (int) (vertCenter - halfGestureHeight) + 1; endY = (int) (vertCenter + halfGestureHeight); } @@ -824,7 +823,7 @@ public final class LauncherInstrumentation { case DOWN: { startX = endX = rect.centerX(); final int vertCenter = rect.centerY(); - final float halfGestureHeight = rect.height() * percent / 2.0f; + final float halfGestureHeight = rect.height() / 2.0f; startY = (int) (vertCenter + halfGestureHeight) - 1; endY = (int) (vertCenter - halfGestureHeight); } @@ -832,7 +831,7 @@ public final class LauncherInstrumentation { case LEFT: { startY = endY = rect.centerY(); final int horizCenter = rect.centerX(); - final float halfGestureWidth = rect.width() * percent / 2.0f; + final float halfGestureWidth = rect.width() / 2.0f; startX = (int) (horizCenter - halfGestureWidth) + 1; endX = (int) (horizCenter + halfGestureWidth); } @@ -840,7 +839,7 @@ public final class LauncherInstrumentation { case RIGHT: { startY = endY = rect.centerY(); final int horizCenter = rect.centerX(); - final float halfGestureWidth = rect.width() * percent / 2.0f; + final float halfGestureWidth = rect.width() / 2.0f; startX = (int) (horizCenter + halfGestureWidth) - 1; endX = (int) (horizCenter - halfGestureWidth); } diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index aabcac282b..51239c9ac4 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -48,7 +48,6 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { mLauncher.scroll( widgetsContainer, Direction.DOWN, - 1f, new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer)), FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { @@ -69,7 +68,6 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { mLauncher.scroll( widgetsContainer, Direction.UP, - 1f, new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0), FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) { diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index da74b66f21..01edcc27d2 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -180,7 +180,7 @@ public final class Workspace extends Home { */ public void flingForward() { final UiObject2 workspace = verifyActiveContainer(); - mLauncher.scroll(workspace, Direction.RIGHT, 1f, + mLauncher.scroll(workspace, Direction.RIGHT, new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0), FLING_STEPS); verifyActiveContainer(); @@ -192,7 +192,7 @@ public final class Workspace extends Home { */ public void flingBackward() { final UiObject2 workspace = verifyActiveContainer(); - mLauncher.scroll(workspace, Direction.LEFT, 1f, + mLauncher.scroll(workspace, Direction.LEFT, new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0), FLING_STEPS); verifyActiveContainer(); From 655074680dd7d691004789d10246a8be90f6fb04 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Wed, 11 Sep 2019 12:29:17 -0700 Subject: [PATCH 049/109] Updates shelf visibility from Launcher to SysUI We used to set shelf visibility (and its height) from Launcher to WM and with the PiP-SysUI migration, this function will be called from Launcher to SysUI directly since SysUI will be the new source of truth for PiP bounds. Bug: 139016518 Test: atest PinnedStackTests Test: Manual Change-Id: Id0931333da76b52ccc6fa23877c72fbe2747203b (cherry picked from commit 95a6dba0784161ed31ef5d3ddf8873c564e4c2b2) --- .../uioverrides/RecentsUiFactory.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index e691566df2..8597f98390 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -22,6 +22,8 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Context; import android.graphics.Rect; +import android.os.RemoteException; +import android.util.Log; import android.view.Gravity; import com.android.launcher3.DeviceProfile; @@ -42,11 +44,12 @@ import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchT import com.android.launcher3.util.TouchController; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper.AsyncCommand; +import com.android.quickstep.RecentsModel; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.TouchInteractionService; import com.android.quickstep.views.RecentsView; -import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.systemui.shared.recents.ISystemUiProxy; import java.util.ArrayList; @@ -56,8 +59,20 @@ import java.util.ArrayList; public abstract class RecentsUiFactory { public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false; - private static final AsyncCommand SET_SHELF_HEIGHT_CMD = (visible, height) -> - WindowManagerWrapper.getInstance().setShelfHeight(visible != 0, height); + + private static final String TAG = RecentsUiFactory.class.getSimpleName(); + + private static AsyncCommand newSetShelfHeightCmd(Context context) { + return (visible, height) -> { + ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(context).getSystemUiProxy(); + if (sysUiProxy == null) return; + try { + sysUiProxy.setShelfHeight(visible != 0, height); + } catch (RemoteException e) { + Log.e(TAG, "Error setShelfHeight", e); + } + }; + } public static RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) { @Override @@ -197,7 +212,7 @@ public abstract class RecentsUiFactory { DeviceProfile profile = launcher.getDeviceProfile(); boolean visible = (state == NORMAL || state == OVERVIEW) && launcher.isUserActive() && !profile.isVerticalBarLayout(); - UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT_CMD, + UiThreadHelper.runAsyncCommand(launcher, newSetShelfHeightCmd(launcher), visible ? 1 : 0, profile.hotseatBarSizePx); if (state == NORMAL) { From b32b6938fdb96b22126fe061e9126471f7eb3304 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 26 Sep 2019 19:12:58 -0700 Subject: [PATCH 050/109] Routing new API calls through a compat layer Change-Id: I0bdbe99d6bc2291b370d143c6b5cb4408fe144eb --- .../com/android/launcher3/uioverrides/RecentsUiFactory.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index 8597f98390..46e883aca3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -48,6 +48,7 @@ import com.android.quickstep.RecentsModel; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.TouchInteractionService; +import com.android.quickstep.util.SharedApiCompat; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.ISystemUiProxy; @@ -67,7 +68,7 @@ public abstract class RecentsUiFactory { ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(context).getSystemUiProxy(); if (sysUiProxy == null) return; try { - sysUiProxy.setShelfHeight(visible != 0, height); + SharedApiCompat.setShelfHeight(sysUiProxy, visible != 0, height); } catch (RemoteException e) { Log.e(TAG, "Error setShelfHeight", e); } From 2611d79f69a5d9250c90db0d57fea6fda84ab105 Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 27 Sep 2019 12:00:09 -0700 Subject: [PATCH 051/109] Deprecating LauncherInstrumentation constructor with parameter Change-Id: I779b4a8fde2db73cced8133f12d1356ad0b8729e --- .../src/com/android/quickstep/FallbackRecentsTest.java | 2 +- .../android/launcher3/ui/AbstractLauncherUiTest.java | 3 +-- .../launcher3/tapl/LauncherInstrumentation.java | 10 ++++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index b8c00e4344..8c11c1c2c8 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -79,7 +79,7 @@ public class FallbackRecentsTest { Context context = instrumentation.getContext(); mDevice = UiDevice.getInstance(instrumentation); mDevice.setOrientationNatural(); - mLauncher = new LauncherInstrumentation(instrumentation); + mLauncher = new LauncherInstrumentation(); mOrderSensitiveRules = RuleChain. outerRule(new NavigationModeSwitchRule(mLauncher)). diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 1f4ba1af0c..b20fae4315 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -92,8 +92,7 @@ public abstract class AbstractLauncherUiTest { protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation()); - protected final LauncherInstrumentation mLauncher = - new LauncherInstrumentation(getInstrumentation()); + protected final LauncherInstrumentation mLauncher = new LauncherInstrumentation(); protected Context mTargetContext; protected String mTargetPackage; diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 1c8f92e917..49d7c79894 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -51,6 +51,7 @@ import android.view.accessibility.AccessibilityEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.By; import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.Configurator; @@ -144,6 +145,15 @@ public final class LauncherInstrumentation { /** * Constructs the root of TAPL hierarchy. You get all other objects from it. */ + public LauncherInstrumentation() { + this(InstrumentationRegistry.getInstrumentation()); + } + + /** + * Constructs the root of TAPL hierarchy. You get all other objects from it. + * Deprecated: use the constructor without parameters instead. + */ + @Deprecated public LauncherInstrumentation(Instrumentation instrumentation) { mInstrumentation = instrumentation; mDevice = UiDevice.getInstance(instrumentation); From 41390b8eea6a4b363d8824949665b18a3c9606c3 Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 27 Sep 2019 14:24:46 -0700 Subject: [PATCH 052/109] Removing a too noisy dropbox diag Change-Id: Ia4dee0b3f20533754b24a91a4a8d2a837bb8e60f --- tests/tapl/com/android/launcher3/tapl/TestHelpers.java | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java index 05c987be29..0c9fda3219 100644 --- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java +++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java @@ -131,7 +131,6 @@ public class TestHelpers { "system_app_anr", "system_app_crash", "system_app_native_crash", - "system_app_wtf", "system_server_anr", "system_server_crash", "system_server_native_crash", From c96fa247a3359ffd26592984d448998061fecc19 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 26 Sep 2019 23:06:32 -0700 Subject: [PATCH 053/109] Fix notification dot scale in AllApps with grid size enabled Test: Manual Bug: 141262820 Change-Id: I24abf822edaeeabf335ed698a3ac1a65b71be7dc --- src/com/android/launcher3/BubbleTextView.java | 16 +++++++++++----- src/com/android/launcher3/DeviceProfile.java | 8 ++++++-- src/com/android/launcher3/folder/FolderIcon.java | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 4d177103d3..7adb6a4420 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -104,6 +104,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private Drawable mIcon; private final boolean mCenterVertically; + private final int mDisplay; + private final CheckLongPressHelper mLongPressHelper; private final StylusEventHelper mStylusEventHelper; private final float mSlop; @@ -155,21 +157,21 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, R.styleable.BubbleTextView, defStyle, 0); mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false); - int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE); + mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE); final int defaultIconSize; - if (display == DISPLAY_WORKSPACE) { + if (mDisplay == DISPLAY_WORKSPACE) { DeviceProfile grid = mActivity.getWallpaperDeviceProfile(); setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); setCompoundDrawablePadding(grid.iconDrawablePaddingPx); defaultIconSize = grid.iconSizePx; mIgnorePaddingTouch = true; - } else if (display == DISPLAY_ALL_APPS) { + } else if (mDisplay == DISPLAY_ALL_APPS) { DeviceProfile grid = mActivity.getDeviceProfile(); setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx); setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx); defaultIconSize = grid.allAppsIconSizePx; mIgnorePaddingTouch = true; - } else if (display == DISPLAY_FOLDER) { + } else if (mDisplay == DISPLAY_FOLDER) { DeviceProfile grid = mActivity.getDeviceProfile(); setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx); setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx); @@ -582,7 +584,11 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mDotInfo = mActivity.getDotInfoForItem(itemInfo); boolean isDotted = mDotInfo != null; float newDotScale = isDotted ? 1f : 0; - mDotRenderer = mActivity.getDeviceProfile().mDotRenderer; + if (mDisplay == DISPLAY_ALL_APPS) { + mDotRenderer = mActivity.getDeviceProfile().mDotRendererAllApps; + } else { + mDotRenderer = mActivity.getDeviceProfile().mDotRendererWorkSpace; + } if (wasDotted || isDotted) { // Animate when a dot is first added or when it is removed. if (animate && (wasDotted ^ isDotted) && isShown()) { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 44c307058d..c034d2de29 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -129,7 +129,8 @@ public class DeviceProfile { private boolean mIsSeascape; // Notification dots - public DotRenderer mDotRenderer; + public DotRenderer mDotRendererWorkSpace; + public DotRenderer mDotRendererAllApps; public DeviceProfile(Context context, InvariantDeviceProfile inv, Point minSize, Point maxSize, @@ -230,8 +231,11 @@ public class DeviceProfile { updateWorkspacePadding(); // This is done last, after iconSizePx is calculated above. - mDotRenderer = new DotRenderer(iconSizePx, IconShape.getShapePath(), + mDotRendererWorkSpace = new DotRenderer(iconSizePx, IconShape.getShapePath(), IconShape.DEFAULT_PATH_SIZE); + mDotRendererAllApps = iconSizePx == allAppsIconSizePx ? mDotRendererWorkSpace : + new DotRenderer(allAppsIconSizePx, IconShape.getShapePath(), + IconShape.DEFAULT_PATH_SIZE); } public DeviceProfile copy(Context context) { diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index a463c7a30f..38406395ab 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -176,7 +176,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel icon.setOnClickListener(ItemClickHandler.INSTANCE); icon.mInfo = folderInfo; icon.mLauncher = launcher; - icon.mDotRenderer = grid.mDotRenderer; + icon.mDotRenderer = grid.mDotRendererWorkSpace; icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title)); Folder folder = Folder.fromXml(launcher); folder.setDragController(launcher.getDragController()); From 3895d9b6429309b9b4567c1401526f50965b3b7b Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 27 Sep 2019 17:55:48 -0700 Subject: [PATCH 054/109] Adding debug tracing for a flake Bug: 141770616 Change-Id: I6413ca6ce380eede817ae2418d5a1bc04c091270 --- src/com/android/launcher3/Workspace.java | 3 +++ .../launcher3/popup/PopupContainerWithArrow.java | 8 ++++++++ src/com/android/launcher3/testing/TestProtocol.java | 1 + .../launcher3/touch/ItemLongClickListener.java | 13 +++++++++++++ 4 files changed, 25 insertions(+) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 6612662ea5..c5e1058971 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1464,6 +1464,9 @@ public class Workspace extends PagedView public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject, DragPreviewProvider previewProvider, DragOptions dragOptions) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_CONTEXT_MENU, "beginDragShared"); + } float iconScale = 1f; if (child instanceof BubbleTextView) { Drawable icon = ((BubbleTextView) child).getIcon(); diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 15fb4cea6f..9857efe8b6 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -36,6 +36,7 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; +import android.util.Log; import android.util.Pair; import android.view.MotionEvent; import android.view.View; @@ -65,6 +66,7 @@ import com.android.launcher3.notification.NotificationKeyData; import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.PackageUserKey; @@ -191,6 +193,9 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, * @return the container if shown or null. */ public static PopupContainerWithArrow showForIcon(BubbleTextView icon) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_CONTEXT_MENU, "showForIcon"); + } Launcher launcher = Launcher.getLauncher(icon.getContext()); if (getOpen(launcher) != null) { // There is already an items container open, so don't open this one. @@ -232,6 +237,9 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, protected void populateAndShow( BubbleTextView icon, ItemInfo item, SystemShortcutFactory factory) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_CONTEXT_MENU, "populateAndShow"); + } PopupDataProvider popupDataProvider = mLauncher.getPopupDataProvider(); populateAndShow(icon, popupDataProvider.getShortcutCountForItem(item), diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index bb44d90a3c..62bb564049 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -84,4 +84,5 @@ public final class TestProtocol { public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824"; public static final String NO_DRAG_TO_WORKSPACE = "b/138729456"; public static final String APP_NOT_DISABLED = "b/139891609"; + public static final String NO_CONTEXT_MENU = "b/141770616"; } diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java index babbcdd16f..0f808c1254 100644 --- a/src/com/android/launcher3/touch/ItemLongClickListener.java +++ b/src/com/android/launcher3/touch/ItemLongClickListener.java @@ -21,6 +21,7 @@ import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; +import android.util.Log; import android.view.View; import android.view.View.OnLongClickListener; @@ -32,6 +33,9 @@ import com.android.launcher3.Launcher; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.folder.Folder; +import com.android.launcher3.testing.TestProtocol; + +import java.util.Arrays; /** * Class to handle long-clicks on workspace items and start drag as a result. @@ -74,10 +78,19 @@ public class ItemLongClickListener { } private static boolean onAllAppsItemLongClick(View v) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_CONTEXT_MENU, "onAllAppsItemLongClick1"); + } Launcher launcher = Launcher.getLauncher(v.getContext()); if (!canStartDrag(launcher)) return false; + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_CONTEXT_MENU, "onAllAppsItemLongClick2"); + } // When we have exited all apps or are in transition, disregard long clicks if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false; + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_CONTEXT_MENU, "onAllAppsItemLongClick3"); + } if (launcher.getWorkspace().isSwitchingState()) return false; // Start the drag From ea38c25854e87b0fe564cff465038a91f4156be2 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Tue, 24 Sep 2019 15:32:18 -0700 Subject: [PATCH 055/109] removed extra test protocol for unit test Bug: 140406263 Test: run TaplTestsLauncher3 Change-Id: I73b3098bd3aa92fed41d22a94cb58fd07263d26a --- src/com/android/launcher3/PagedView.java | 7 ------- .../launcher3/testing/TestInformationHandler.java | 8 -------- src/com/android/launcher3/testing/TestProtocol.java | 2 -- tests/tapl/com/android/launcher3/tapl/Workspace.java | 11 +++++------ 4 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 34b102c0b7..5c790f3797 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1708,11 +1708,4 @@ public abstract class PagedView extends ViewGrou mTmpIntPair[1] = rightChild; return mTmpIntPair; } - - /** - * Returns true if overscroll is allowed, otherwise false. - */ - public boolean allowOverScroll() { - return mAllowOverScroll; - } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index d62b591b8c..d3ec83b4fb 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -82,14 +82,6 @@ public class TestInformationHandler implements ResourceBasedOverride { break; } - case TestProtocol.REQUEST_DOES_WORKSPACE_HAVE_SECOND_PAGE: { - if (mLauncher == null) return null; - - response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, - mLauncher.getWorkspace().getPageCount() > 1); - break; - } - case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: { response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true); break; diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index f9f59d8b68..62bb564049 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -66,8 +66,6 @@ public final class TestProtocol { "all-apps-to-overview-swipe-height"; public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT = "home-to-all-apps-swipe-height"; - public static final String REQUEST_DOES_WORKSPACE_HAVE_SECOND_PAGE = - "does-workspace-have-second-page"; public static final String REQUEST_HOTSEAT_TOP = "hotseat-top"; public static final String REQUEST_IS_LAUNCHER_INITIALIZED = "is-launcher-initialized"; public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list"; diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index ad2feb4b5d..0aa36ddbbe 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -22,7 +22,6 @@ import static junit.framework.TestCase.assertTrue; import android.graphics.Point; import android.graphics.Rect; -import android.os.Bundle; import android.os.SystemClock; import android.view.KeyEvent; import android.view.MotionEvent; @@ -124,7 +123,7 @@ public final class Workspace extends Home { */ public void ensureWorkspaceIsScrollable() { final UiObject2 workspace = verifyActiveContainer(); - if (!isWorkspaceScrollable()) { + if (!isWorkspaceScrollable(workspace)) { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "dragging icon to a second page of workspace to make it scrollable")) { dragIconToWorkspace( @@ -136,12 +135,12 @@ public final class Workspace extends Home { verifyActiveContainer(); } } - assertTrue("Home screen workspace didn't become scrollable", isWorkspaceScrollable()); + assertTrue("Home screen workspace didn't become scrollable", + isWorkspaceScrollable(workspace)); } - private boolean isWorkspaceScrollable() { - Bundle result = mLauncher.getTestInfo(TestProtocol.REQUEST_DOES_WORKSPACE_HAVE_SECOND_PAGE); - return result.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, false); + private boolean isWorkspaceScrollable(UiObject2 workspace) { + return workspace.getChildCount() > 1; } @NonNull From 5d58d25ea3e335b4f5e118ac3b5da5ec6800b501 Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 30 Sep 2019 12:22:01 -0700 Subject: [PATCH 056/109] fixingtypo Change-Id: I0d9d9f3f712fc90e82e7660c14ea31779648614a --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index d89ec8b5d4..52971d92fe 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -550,7 +550,7 @@ public final class LauncherInstrumentation { displaySize.x / 2, displaySize.y - 1, displaySize.x / 2, 0, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME); - assertTrue("Context menu is still visible afterswiping up to home", + assertTrue("Context menu is still visible after swiping up to home", !hasLauncherObject("deep_shortcuts_container")); } if (hasLauncherObject(WORKSPACE_RES_ID)) { From ee3db65eccaa2df62b2fb09932fe6ce3625e31a6 Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 30 Sep 2019 12:48:47 -0700 Subject: [PATCH 057/109] Not unlocking phone on the test start Somehow tests unlock the phone anyways. Bug: 141772190 Change-Id: I66de70ec10a7e9ae05ba942570bf9eff9d9e7a82 --- tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index b20fae4315..843fd33c63 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -171,8 +171,6 @@ public abstract class AbstractLauncherUiTest { mTargetContext = InstrumentationRegistry.getTargetContext(); mTargetPackage = mTargetContext.getPackageName(); - // Unlock the phone - mDevice.executeShellCommand("input keyevent 82"); } @After From 9a8462117d873ac88244e0af821b955a2a46dcae Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Thu, 5 Sep 2019 11:47:12 -0700 Subject: [PATCH 058/109] Set exclusion rect for launcher before it gains focus Back gesture still shows if user attempts to swipe back while we're animating to launcher state normal. Focus is only granted after the animation has completed, but the user can interact w/ the back edge panels while it's ongoing. fixes: 138622418 Test: Open app, swipe home and quickly swipe from the edge of the screen. Should go to -1 screen and not see back arrow. Change-Id: I32228370c7ec1bdb75474fdff2d1c99cb677fa6a --- .../quickstep/LauncherActivityControllerHelper.java | 10 +++++++++- src/com/android/launcher3/LauncherRootView.java | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index d7afd328db..46ba2a41a2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -109,6 +109,14 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe // Ensure recents is at the correct position for NORMAL state. For example, when we detach // recents, we assume the first task is invisible, making translation off by one task. activity.getStateManager().reapplyState(); + setLauncherHideBackArrow(false); + } + + private void setLauncherHideBackArrow(boolean hideBackArrow) { + Launcher launcher = getCreatedActivity(); + if (launcher != null) { + launcher.getRootView().setForceHideBackArrow(hideBackArrow); + } } @Override @@ -139,7 +147,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe ? FloatingIconView.getFloatingIconView(activity, workspaceView, true /* hideOriginal */, iconLocation, false /* isOpening */) : null; - + setLauncherHideBackArrow(true); return new HomeAnimationFactory() { @Nullable @Override diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java index f964b8d9ee..ce1795aa11 100644 --- a/src/com/android/launcher3/LauncherRootView.java +++ b/src/com/android/launcher3/LauncherRootView.java @@ -39,6 +39,8 @@ public class LauncherRootView extends InsettableFrameLayout { private WindowStateListener mWindowStateListener; @ViewDebug.ExportedProperty(category = "launcher") private boolean mDisallowBackGesture; + @ViewDebug.ExportedProperty(category = "launcher") + private boolean mForceHideBackArrow; public LauncherRootView(Context context, AttributeSet attrs) { super(context, attrs); @@ -175,13 +177,19 @@ public class LauncherRootView extends InsettableFrameLayout { setDisallowBackGesture(mDisallowBackGesture); } + @TargetApi(Build.VERSION_CODES.Q) + public void setForceHideBackArrow(boolean forceHideBackArrow) { + this.mForceHideBackArrow = forceHideBackArrow; + setDisallowBackGesture(mDisallowBackGesture); + } + @TargetApi(Build.VERSION_CODES.Q) public void setDisallowBackGesture(boolean disallowBackGesture) { if (!Utilities.ATLEAST_Q) { return; } mDisallowBackGesture = disallowBackGesture; - setSystemGestureExclusionRects(mDisallowBackGesture + setSystemGestureExclusionRects((mForceHideBackArrow || mDisallowBackGesture) ? SYSTEM_GESTURE_EXCLUSION_RECT : Collections.emptyList()); } From 045b4fab764d5722bede13c28269e76d6eae0c1a Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 20 Sep 2019 12:51:37 -0700 Subject: [PATCH 059/109] Removing static listeners from PackageInstallerCompat Bug: 141376165 Change-Id: I2b49d53a05a04c622ed5a7b723109a6cc230d230 --- .../launcher3/icons/cache/BaseIconCache.java | 2 +- .../PackageInstallStateChangedTaskTest.java | 5 +- .../android/launcher3/LauncherAppState.java | 11 +- src/com/android/launcher3/LauncherModel.java | 99 +++--- src/com/android/launcher3/PromiseAppInfo.java | 8 +- .../launcher3/SessionCommitReceiver.java | 6 +- .../launcher3/compat/LauncherAppsCompat.java | 7 +- .../compat/LauncherAppsCompatVL.java | 12 +- .../compat/LauncherAppsCompatVQ.java | 36 --- .../compat/PackageInstallerCompat.java | 118 ------- .../compat/PackageInstallerCompatVL.java | 287 ------------------ .../android/launcher3/icons/IconCache.java | 6 + .../model/AddWorkspaceItemsTask.java | 4 +- .../android/launcher3/model/AllAppsList.java | 16 +- .../model/GridSizeMigrationTask.java | 10 +- .../android/launcher3/model/LoaderTask.java | 9 +- .../model/PackageInstallStateChangedTask.java | 10 +- .../launcher3/pm/InstallSessionTracker.java | 129 ++++++++ .../launcher3/pm/PackageInstallInfo.java | 60 ++++ .../launcher3/pm/PackageInstallerCompat.java | 220 ++++++++++++++ .../launcher3/touch/ItemClickHandler.java | 4 +- .../launcher3/ui/widget/BindWidgetTest.java | 4 +- 22 files changed, 520 insertions(+), 543 deletions(-) delete mode 100644 src/com/android/launcher3/compat/LauncherAppsCompatVQ.java delete mode 100644 src/com/android/launcher3/compat/PackageInstallerCompat.java delete mode 100644 src/com/android/launcher3/compat/PackageInstallerCompatVL.java create mode 100644 src/com/android/launcher3/pm/InstallSessionTracker.java create mode 100644 src/com/android/launcher3/pm/PackageInstallInfo.java create mode 100644 src/com/android/launcher3/pm/PackageInstallerCompat.java diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java index a886c0aa09..93f0538bd5 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java @@ -374,7 +374,7 @@ public abstract class BaseIconCache { * Adds a default package entry in the cache. This entry is not persisted and will be removed * when the cache is flushed. */ - public synchronized void cachePackageInstallInfo(String packageName, UserHandle user, + protected synchronized void cachePackageInstallInfo(String packageName, UserHandle user, Bitmap icon, CharSequence title) { removeFromMemCacheLocked(packageName, user); diff --git a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java index 42a4f5cc99..a1a456149f 100644 --- a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java @@ -5,8 +5,7 @@ import static org.junit.Assert.assertEquals; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.compat.PackageInstallerCompat; -import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; +import com.android.launcher3.pm.PackageInstallInfo; import org.junit.Before; import org.junit.Test; @@ -28,7 +27,7 @@ public class PackageInstallStateChangedTaskTest extends BaseModelUpdateTaskTestC } private PackageInstallStateChangedTask newTask(String pkg, int progress) { - int state = PackageInstallerCompat.STATUS_INSTALLING; + int state = PackageInstallInfo.STATUS_INSTALLING; PackageInstallInfo installInfo = new PackageInstallInfo(pkg, state, progress, android.os.Process.myUserHandle()); return new PackageInstallStateChangedTask(installInfo); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index db94bdb8c4..efb3d36bf1 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -17,6 +17,7 @@ package com.android.launcher3; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver; import android.content.ComponentName; @@ -28,12 +29,13 @@ import android.os.Handler; import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.notification.NotificationListener; +import com.android.launcher3.pm.InstallSessionTracker; +import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SecureSettingsObserver; @@ -54,6 +56,8 @@ public class LauncherAppState { private final InvariantDeviceProfile mInvariantDeviceProfile; private final SecureSettingsObserver mNotificationDotsObserver; + private final InstallSessionTracker mInstallSessionTracker; + public static LauncherAppState getInstance(final Context context) { return INSTANCE.get(context); } @@ -102,6 +106,9 @@ public class LauncherAppState { mInvariantDeviceProfile.addOnChangeListener(this::onIdpChanged); new Handler().post( () -> mInvariantDeviceProfile.verifyConfigChangedInBackground(context)); + mInstallSessionTracker = PackageInstallerCompat.getInstance(context) + .registerInstallTracker(mModel, MODEL_EXECUTOR); + if (!mContext.getResources().getBoolean(R.bool.notification_dots_enabled)) { mNotificationDotsObserver = null; } else { @@ -141,7 +148,7 @@ public class LauncherAppState { mContext.unregisterReceiver(mModel); final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); launcherApps.removeOnAppsChangedCallback(mModel); - PackageInstallerCompat.getInstance(mContext).onStop(); + mInstallSessionTracker.unregister(); if (mNotificationDotsObserver != null) { mNotificationDotsObserver.unregister(); } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index c0cf135441..f360325194 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -24,8 +24,8 @@ import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageInstaller; import android.content.pm.ShortcutInfo; -import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; @@ -34,8 +34,8 @@ import android.util.Pair; import androidx.annotation.Nullable; import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.logging.FileLog; @@ -52,6 +52,8 @@ import com.android.launcher3.model.PackageInstallStateChangedTask; import com.android.launcher3.model.PackageUpdatedTask; import com.android.launcher3.model.ShortcutsChangedTask; import com.android.launcher3.model.UserLockStateChangedTask; +import com.android.launcher3.pm.InstallSessionTracker; +import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.ItemInfoMatcher; @@ -75,7 +77,7 @@ import java.util.function.Supplier; * for the Launcher. */ public class LauncherModel extends BroadcastReceiver - implements LauncherAppsCompat.OnAppsChangedCallbackCompat { + implements LauncherAppsCompat.OnAppsChangedCallbackCompat, InstallSessionTracker.Callback { private static final boolean DEBUG_RECEIVER = false; static final String TAG = "Launcher.Model"; @@ -127,20 +129,6 @@ public class LauncherModel extends BroadcastReceiver mBgAllAppsList = new AllAppsList(iconCache, appFilter); } - public void setPackageState(PackageInstallInfo installInfo) { - enqueueModelUpdateTask(new PackageInstallStateChangedTask(installInfo)); - } - - /** - * Updates the icons and label of all pending icons for the provided package name. - */ - public void updateSessionDisplayInfo(final String packageName) { - HashSet packages = new HashSet<>(); - packages.add(packageName); - enqueueModelUpdateTask(new CacheDataUpdatedTask( - CacheDataUpdatedTask.OP_SESSION_UPDATE, Process.myUserHandle(), packages)); - } - /** * Adds the provided items to the workspace. */ @@ -173,30 +161,6 @@ public class LauncherModel extends BroadcastReceiver enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName)); } - public void onSessionFailure(String packageName, UserHandle user) { - enqueueModelUpdateTask(new BaseModelUpdateTask() { - @Override - public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { - final IntSparseArrayMap removedIds = new IntSparseArrayMap<>(); - synchronized (dataModel) { - for (ItemInfo info : dataModel.itemsIdMap) { - if (info instanceof WorkspaceItemInfo - && ((WorkspaceItemInfo) info).hasPromiseIconUi() - && user.equals(info.user) - && info.getIntent() != null - && TextUtils.equals(packageName, info.getIntent().getPackage())) { - removedIds.put(info.id, true /* remove */); - } - } - } - - if (!removedIds.isEmpty()) { - deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds, false)); - } - } - }); - } - @Override public void onPackageRemoved(String packageName, UserHandle user) { onPackagesRemoved(user, packageName); @@ -392,16 +356,65 @@ public class LauncherModel extends BroadcastReceiver } } + @Override public void onInstallSessionCreated(final PackageInstallInfo sessionInfo) { + if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) { + enqueueModelUpdateTask(new BaseModelUpdateTask() { + @Override + public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { + apps.addPromiseApp(app.getContext(), sessionInfo); + bindApplicationsIfNeeded(); + } + }); + } + } + + @Override + public void onSessionFailure(String packageName, UserHandle user) { + if (!FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()) { + return; + } enqueueModelUpdateTask(new BaseModelUpdateTask() { @Override public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { - apps.addPromiseApp(app.getContext(), sessionInfo); - bindApplicationsIfNeeded(); + final IntSparseArrayMap removedIds = new IntSparseArrayMap<>(); + synchronized (dataModel) { + for (ItemInfo info : dataModel.itemsIdMap) { + if (info instanceof WorkspaceItemInfo + && ((WorkspaceItemInfo) info).hasPromiseIconUi() + && user.equals(info.user) + && info.getIntent() != null + && TextUtils.equals(packageName, info.getIntent().getPackage())) { + removedIds.put(info.id, true /* remove */); + } + } + } + + if (!removedIds.isEmpty()) { + deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedIds, false)); + } } }); } + @Override + public void onPackageStateChanged(PackageInstallInfo installInfo) { + enqueueModelUpdateTask(new PackageInstallStateChangedTask(installInfo)); + } + + /** + * Updates the icons and label of all pending icons for the provided package name. + */ + @Override + public void onUpdateSessionDisplay(PackageUserKey key, PackageInstaller.SessionInfo info) { + mApp.getIconCache().updateSessionCache(key, info); + + HashSet packages = new HashSet<>(); + packages.add(key.mPackageName); + enqueueModelUpdateTask(new CacheDataUpdatedTask( + CacheDataUpdatedTask.OP_SESSION_UPDATE, key.mUser, packages)); + } + public class LoaderTransaction implements AutoCloseable { private final LoaderTask mTask; diff --git a/src/com/android/launcher3/PromiseAppInfo.java b/src/com/android/launcher3/PromiseAppInfo.java index 4ad0b3d16e..e55e4bd651 100644 --- a/src/com/android/launcher3/PromiseAppInfo.java +++ b/src/com/android/launcher3/PromiseAppInfo.java @@ -19,16 +19,16 @@ package com.android.launcher3; import android.content.Context; import android.content.Intent; -import com.android.launcher3.compat.PackageInstallerCompat; -import com.android.launcher3.util.PackageManagerHelper; - import androidx.annotation.NonNull; +import com.android.launcher3.pm.PackageInstallInfo; +import com.android.launcher3.util.PackageManagerHelper; + public class PromiseAppInfo extends AppInfo { public int level = 0; - public PromiseAppInfo(@NonNull PackageInstallerCompat.PackageInstallInfo installInfo) { + public PromiseAppInfo(@NonNull PackageInstallInfo installInfo) { componentName = installInfo.componentName; intent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_LAUNCHER) diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index 6853bf6941..55402dd59b 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -16,6 +16,8 @@ package com.android.launcher3; +import static com.android.launcher3.pm.PackageInstallerCompat.getUserHandle; + import android.annotation.TargetApi; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -38,13 +40,11 @@ import android.text.TextUtils; import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.util.Executors; -import com.android.launcher3.compat.PackageInstallerCompat; import java.util.List; -import static com.android.launcher3.compat.PackageInstallerCompat.getUserHandle; - /** * BroadcastReceiver to handle session commit intent. */ diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java index cdb5c4d2b7..047346dcaf 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompat.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; -import android.content.pm.PackageInstaller; import android.content.pm.ShortcutInfo; import android.graphics.Rect; import android.os.Bundle; @@ -59,9 +58,7 @@ public abstract class LauncherAppsCompat { public static LauncherAppsCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - if (Utilities.ATLEAST_Q) { - sInstance = new LauncherAppsCompatVQ(context.getApplicationContext()); - } else if (Utilities.ATLEAST_OREO) { + if (Utilities.ATLEAST_OREO) { sInstance = new LauncherAppsCompatVO(context.getApplicationContext()); } else { sInstance = new LauncherAppsCompatVL(context.getApplicationContext()); @@ -88,6 +85,4 @@ public abstract class LauncherAppsCompat { UserHandle user); public abstract List getCustomShortcutActivityList( @Nullable PackageUserKey packageUser); - - public abstract List getAllPackageInstallerSessions(); } diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java index 1885d8f03d..f1b9756e4a 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; -import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; @@ -33,6 +32,9 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.PackageUserKey; @@ -41,9 +43,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - public class LauncherAppsCompatVL extends LauncherAppsCompat { protected final LauncherApps mLauncherApps; @@ -207,10 +206,5 @@ public class LauncherAppsCompatVL extends LauncherAppsCompat { } return result; } - - @Override - public List getAllPackageInstallerSessions() { - return mContext.getPackageManager().getPackageInstaller().getAllSessions(); - } } diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVQ.java b/src/com/android/launcher3/compat/LauncherAppsCompatVQ.java deleted file mode 100644 index 0a1811e341..0000000000 --- a/src/com/android/launcher3/compat/LauncherAppsCompatVQ.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.compat; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInstaller; - -import java.util.List; - -@TargetApi(29) -public class LauncherAppsCompatVQ extends LauncherAppsCompatVO { - - LauncherAppsCompatVQ(Context context) { - super(context); - } - - public List getAllPackageInstallerSessions() { - return mLauncherApps.getAllPackageInstallerSessions(); - } -} diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java deleted file mode 100644 index 55df98b48f..0000000000 --- a/src/com/android/launcher3/compat/PackageInstallerCompat.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2014 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.compat; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageInstaller; -import android.content.pm.PackageInstaller.SessionInfo; -import android.os.Process; -import android.os.UserHandle; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -import androidx.annotation.NonNull; - -import com.android.launcher3.Utilities; -import com.android.launcher3.util.PackageUserKey; - -public abstract class PackageInstallerCompat { - - // Set of session ids of promise icons that have been added to the home screen - // as FLAG_PROMISE_NEW_INSTALLS. - protected static final String PROMISE_ICON_IDS = "promise_icon_ids"; - - public static final int STATUS_INSTALLED = 0; - public static final int STATUS_INSTALLING = 1; - public static final int STATUS_FAILED = 2; - - private static final Object sInstanceLock = new Object(); - private static PackageInstallerCompat sInstance; - - public static PackageInstallerCompat getInstance(Context context) { - synchronized (sInstanceLock) { - if (sInstance == null) { - sInstance = new PackageInstallerCompatVL(context); - } - return sInstance; - } - } - - public static UserHandle getUserHandle(SessionInfo info) { - return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle(); - } - - /** - * @return a map of active installs to their progress - */ - public abstract HashMap updateAndGetActiveSessionCache(); - - /** - * @return an active SessionInfo for {@param pkg} or null if none exists. - */ - public abstract SessionInfo getActiveSessionInfo(UserHandle user, String pkg); - - public abstract void onStop(); - - public static final class PackageInstallInfo { - public final ComponentName componentName; - public final String packageName; - public final int state; - public final int progress; - public final UserHandle user; - - private PackageInstallInfo(@NonNull SessionInfo info) { - this.state = STATUS_INSTALLING; - this.packageName = info.getAppPackageName(); - this.componentName = new ComponentName(packageName, ""); - this.progress = (int) (info.getProgress() * 100f); - this.user = getUserHandle(info); - } - - public PackageInstallInfo(String packageName, int state, int progress, UserHandle user) { - this.state = state; - this.packageName = packageName; - this.componentName = new ComponentName(packageName, ""); - this.progress = progress; - this.user = user; - } - - public static PackageInstallInfo fromInstallingState(SessionInfo info) { - return new PackageInstallInfo(info); - } - - public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) { - return new PackageInstallInfo(packageName, state, 0 /* progress */, user); - } - - } - - public abstract List getAllVerifiedSessions(); - - /** - * Returns true if a promise icon was already added to the home screen for {@param sessionId}. - * Applicable only for icons with flag FLAG_PROMISE_NEW_INSTALLS. - */ - public abstract boolean promiseIconAddedForId(int sessionId); - - /** - * Applicable only for icons with flag FLAG_PROMISE_NEW_INSTALLS. - */ - public abstract void removePromiseIconId(int sessionId); -} diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java deleted file mode 100644 index f421f7c016..0000000000 --- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2014 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.compat; - -import static com.android.launcher3.Utilities.getPrefs; -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInstaller; -import android.content.pm.PackageInstaller.SessionCallback; -import android.content.pm.PackageInstaller.SessionInfo; -import android.content.pm.PackageManager; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.SparseArray; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherModel; -import com.android.launcher3.SessionCommitReceiver; -import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.icons.IconCache; -import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.IntSet; -import com.android.launcher3.util.PackageUserKey; -import com.android.launcher3.util.Thunk; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - -public class PackageInstallerCompatVL extends PackageInstallerCompat { - - private static final boolean DEBUG = false; - - @Thunk final SparseArray mActiveSessions = new SparseArray<>(); - - @Thunk final PackageInstaller mInstaller; - private final IconCache mCache; - private final Context mAppContext; - private final HashMap mSessionVerifiedMap = new HashMap<>(); - private final LauncherAppsCompat mLauncherApps; - private final IntSet mPromiseIconIds; - - PackageInstallerCompatVL(Context context) { - mAppContext = context.getApplicationContext(); - mInstaller = context.getPackageManager().getPackageInstaller(); - mCache = LauncherAppState.getInstance(context).getIconCache(); - mInstaller.registerSessionCallback(mCallback, MODEL_EXECUTOR.getHandler()); - mLauncherApps = LauncherAppsCompat.getInstance(context); - mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString( - getPrefs(context).getString(PROMISE_ICON_IDS, ""))); - - cleanUpPromiseIconIds(); - } - - private void cleanUpPromiseIconIds() { - IntArray existingIds = new IntArray(); - for (SessionInfo info : updateAndGetActiveSessionCache().values()) { - existingIds.add(info.getSessionId()); - } - IntArray idsToRemove = new IntArray(); - - for (int i = mPromiseIconIds.size() - 1; i >= 0; --i) { - if (!existingIds.contains(mPromiseIconIds.getArray().get(i))) { - idsToRemove.add(mPromiseIconIds.getArray().get(i)); - } - } - for (int i = idsToRemove.size() - 1; i >= 0; --i) { - mPromiseIconIds.getArray().removeValue(idsToRemove.get(i)); - } - } - - @Override - public HashMap updateAndGetActiveSessionCache() { - HashMap activePackages = new HashMap<>(); - for (SessionInfo info : getAllVerifiedSessions()) { - addSessionInfoToCache(info, getUserHandle(info)); - if (info.getAppPackageName() != null) { - activePackages.put(new PackageUserKey(info.getAppPackageName(), - getUserHandle(info)), info); - mActiveSessions.put(info.getSessionId(), - new PackageUserKey(info.getAppPackageName(), getUserHandle(info))); - } - } - return activePackages; - } - - public SessionInfo getActiveSessionInfo(UserHandle user, String pkg) { - for (SessionInfo info : getAllVerifiedSessions()) { - boolean match = pkg.equals(info.getAppPackageName()); - if (Utilities.ATLEAST_Q && !user.equals(getUserHandle(info))) { - match = false; - } - if (match) { - return info; - } - } - return null; - } - - @Thunk void addSessionInfoToCache(SessionInfo info, UserHandle user) { - String packageName = info.getAppPackageName(); - if (packageName != null) { - mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(), - info.getAppLabel()); - } - } - - @Override - public void onStop() { - mInstaller.unregisterSessionCallback(mCallback); - } - - @Thunk void sendUpdate(PackageInstallInfo info) { - LauncherAppState app = LauncherAppState.getInstanceNoCreate(); - if (app != null) { - app.getModel().setPackageState(info); - } - } - - /** - * Add a promise app icon to the workspace iff: - * - The settings for it are enabled - * - The user installed the app - * - There is an app icon and label (For apps with no launching activity, no icon is provided). - * - The app is not already installed - * - A promise icon for the session has not already been created - */ - private void tryQueuePromiseAppIcon(SessionInfo sessionInfo) { - if (Utilities.ATLEAST_OREO && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get() - && SessionCommitReceiver.isEnabled(mAppContext) - && verify(sessionInfo) != null - && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER - && sessionInfo.getAppIcon() != null - && !TextUtils.isEmpty(sessionInfo.getAppLabel()) - && !mPromiseIconIds.contains(sessionInfo.getSessionId()) - && mLauncherApps.getApplicationInfo(sessionInfo.getAppPackageName(), 0, - getUserHandle(sessionInfo)) == null) { - SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo); - mPromiseIconIds.add(sessionInfo.getSessionId()); - updatePromiseIconPrefs(); - } - } - - private final SessionCallback mCallback = new SessionCallback() { - - @Override - public void onCreated(int sessionId) { - SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId); - if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get() && sessionInfo != null) { - LauncherAppState app = LauncherAppState.getInstanceNoCreate(); - if (app != null) { - app.getModel().onInstallSessionCreated( - PackageInstallInfo.fromInstallingState(sessionInfo)); - } - } - - tryQueuePromiseAppIcon(sessionInfo); - } - - @Override - public void onFinished(int sessionId, boolean success) { - // For a finished session, we can't get the session info. So use the - // packageName from our local cache. - PackageUserKey key = mActiveSessions.get(sessionId); - mActiveSessions.remove(sessionId); - - if (key != null && key.mPackageName != null) { - String packageName = key.mPackageName; - sendUpdate(PackageInstallInfo.fromState(success ? STATUS_INSTALLED : STATUS_FAILED, - packageName, key.mUser)); - - if (!success && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get() - && mPromiseIconIds.contains(sessionId)) { - LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); - if (appState != null) { - appState.getModel().onSessionFailure(packageName, key.mUser); - } - // If it is successful, the id is removed in the the package added flow. - removePromiseIconId(sessionId); - } - } - } - - @Override - public void onProgressChanged(int sessionId, float progress) { - SessionInfo session = verify(mInstaller.getSessionInfo(sessionId)); - if (session != null && session.getAppPackageName() != null) { - sendUpdate(PackageInstallInfo.fromInstallingState(session)); - } - } - - @Override - public void onActiveChanged(int sessionId, boolean active) { } - - @Override - public void onBadgingChanged(int sessionId) { - SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId); - if (sessionInfo != null) { - tryQueuePromiseAppIcon(sessionInfo); - } - } - - private SessionInfo pushSessionDisplayToLauncher(int sessionId) { - SessionInfo session = verify(mInstaller.getSessionInfo(sessionId)); - if (session != null && session.getAppPackageName() != null) { - mActiveSessions.put(session.getSessionId(), - new PackageUserKey(session.getAppPackageName(), getUserHandle(session))); - addSessionInfoToCache(session, getUserHandle(session)); - LauncherAppState app = LauncherAppState.getInstanceNoCreate(); - if (app != null) { - app.getModel().updateSessionDisplayInfo(session.getAppPackageName()); - } - return session; - } - return null; - } - }; - - private PackageInstaller.SessionInfo verify(PackageInstaller.SessionInfo sessionInfo) { - if (sessionInfo == null - || sessionInfo.getInstallerPackageName() == null - || TextUtils.isEmpty(sessionInfo.getAppPackageName())) { - return null; - } - String pkg = sessionInfo.getInstallerPackageName(); - synchronized (mSessionVerifiedMap) { - if (!mSessionVerifiedMap.containsKey(pkg)) { - LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext); - boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg, - ApplicationInfo.FLAG_SYSTEM, getUserHandle(sessionInfo)) != null; - mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag); - } - } - return mSessionVerifiedMap.get(pkg) ? sessionInfo : null; - } - - @Override - public List getAllVerifiedSessions() { - List list = new ArrayList<>(Utilities.ATLEAST_Q - ? mLauncherApps.getAllPackageInstallerSessions() - : mInstaller.getAllSessions()); - Iterator it = list.iterator(); - while (it.hasNext()) { - if (verify(it.next()) == null) { - it.remove(); - } - } - return list; - } - - @Override - public boolean promiseIconAddedForId(int sessionId) { - return mPromiseIconIds.contains(sessionId); - } - - @Override - public void removePromiseIconId(int sessionId) { - if (mPromiseIconIds.contains(sessionId)) { - mPromiseIconIds.getArray().removeValue(sessionId); - updatePromiseIconPrefs(); - } - } - - private void updatePromiseIconPrefs() { - getPrefs(mAppContext).edit() - .putString(PROMISE_ICON_IDS, mPromiseIconIds.getArray().toConcatString()) - .apply(); - } -} diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 11c7f20537..c0a095d57d 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ShortcutInfo; @@ -52,6 +53,7 @@ import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.InstantAppResolver; +import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; import java.util.function.Supplier; @@ -247,6 +249,10 @@ public class IconCache extends BaseIconCache { return mIconProvider.getIcon(info, mIconDpi, flattenDrawable); } + public void updateSessionCache(PackageUserKey key, PackageInstaller.SessionInfo info) { + cachePackageInstallInfo(key.mPackageName, key.mUser, info.getAppIcon(), info.getAppLabel()); + } + @Override protected String getIconSystemState(String packageName) { return mIconProvider.getSystemStateForPackage(mSystemState, packageName) diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index dfd5a708bf..844a2a61a1 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -29,11 +29,11 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherModel.CallbackTask; -import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.model.BgDataModel.Callbacks; +import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 3873a17e03..1e1df88d39 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -28,14 +28,16 @@ import android.os.Process; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.launcher3.AppFilter; import com.android.launcher3.AppInfo; import com.android.launcher3.PromiseAppInfo; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.compat.PackageInstallerCompat; -import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.icons.IconCache; +import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.SafeCloseable; @@ -46,9 +48,6 @@ import java.util.HashSet; import java.util.List; import java.util.function.Consumer; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - /** * Stores the list of all applications for the all apps view. @@ -110,8 +109,7 @@ public class AllAppsList { mDataChanged = true; } - public void addPromiseApp(Context context, - PackageInstallerCompat.PackageInstallInfo installInfo) { + public void addPromiseApp(Context context, PackageInstallInfo installInfo) { ApplicationInfo applicationInfo = LauncherAppsCompat.getInstance(context) .getApplicationInfo(installInfo.packageName, 0, installInfo.user); // only if not yet installed @@ -134,10 +132,10 @@ public class AllAppsList { && appInfo.user.equals(user) && appInfo instanceof PromiseAppInfo) { final PromiseAppInfo promiseAppInfo = (PromiseAppInfo) appInfo; - if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLING) { + if (installInfo.state == PackageInstallInfo.STATUS_INSTALLING) { promiseAppInfo.level = installInfo.progress; return promiseAppInfo; - } else if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) { + } else if (installInfo.state == PackageInstallInfo.STATUS_FAILED) { removeApp(i); } } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index 783e908e30..ac44b0e0bb 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -17,6 +17,8 @@ import android.graphics.Point; import android.util.Log; import android.util.SparseArray; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; @@ -27,21 +29,17 @@ import com.android.launcher3.LauncherSettings.Settings; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSparseArrayMap; -import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.function.Consumer; - -import androidx.annotation.VisibleForTesting; /** * This class takes care of shrinking the workspace (by maximum of one row and one column), as a @@ -973,7 +971,7 @@ public class GridSizeMigrationTask { validPackages.add(info.packageName); } PackageInstallerCompat.getInstance(context) - .updateAndGetActiveSessionCache().keySet() + .getActiveSessions().keySet() .forEach(packageUserKey -> validPackages.add(packageUserKey.mPackageName)); return validPackages; } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index ad6b5c40e6..4c88eb73fd 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -53,7 +53,6 @@ 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; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; @@ -66,6 +65,8 @@ import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.ShortcutCachingLogic; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; import com.android.launcher3.logging.FileLog; +import com.android.launcher3.pm.PackageInstallInfo; +import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.provider.ImportDataTask; import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.shortcuts.DeepShortcutManager; @@ -297,7 +298,9 @@ public class LoaderTask implements Runnable { mBgDataModel.clear(); final HashMap installingPkgs = - mPackageInstaller.updateAndGetActiveSessionCache(); + mPackageInstaller.getActiveSessions(); + installingPkgs.forEach(mApp.getIconCache()::updateSessionCache); + final PackageUserKey tempPackageKey = new PackageUserKey(null, null); mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); @@ -856,7 +859,7 @@ public class LoaderTask implements Runnable { for (PackageInstaller.SessionInfo info : mPackageInstaller.getAllVerifiedSessions()) { mBgAllAppsList.addPromiseApp(mApp.getContext(), - PackageInstallerCompat.PackageInstallInfo.fromInstallingState(info)); + PackageInstallInfo.fromInstallingState(info)); } } diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java index 802cbc7c5e..2832150d23 100644 --- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java +++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java @@ -19,16 +19,14 @@ import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import com.android.launcher3.AppInfo; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherModel.CallbackTask; -import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.PromiseAppInfo; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.compat.PackageInstallerCompat; -import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; +import com.android.launcher3.model.BgDataModel.Callbacks; +import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.InstantAppResolver; import java.util.HashSet; @@ -46,7 +44,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { @Override public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { - if (mInstallInfo.state == PackageInstallerCompat.STATUS_INSTALLED) { + if (mInstallInfo.state == PackageInstallInfo.STATUS_INSTALLED) { try { // For instant apps we do not get package-add. Use setting events to update // any pinned icons. @@ -79,7 +77,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask { if (si.hasPromiseIconUi() && (cn != null) && mInstallInfo.packageName.equals(cn.getPackageName())) { si.setInstallProgress(mInstallInfo.progress); - if (mInstallInfo.state == PackageInstallerCompat.STATUS_FAILED) { + if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) { // Mark this info as broken. si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE; } diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java new file mode 100644 index 0000000000..f157603e1a --- /dev/null +++ b/src/com/android/launcher3/pm/InstallSessionTracker.java @@ -0,0 +1,129 @@ +/* + * 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.pm; + +import static com.android.launcher3.pm.PackageInstallInfo.STATUS_FAILED; +import static com.android.launcher3.pm.PackageInstallInfo.STATUS_INSTALLED; +import static com.android.launcher3.pm.PackageInstallerCompat.getUserHandle; + +import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; +import android.os.UserHandle; +import android.util.SparseArray; + +import com.android.launcher3.util.PackageUserKey; + +public class InstallSessionTracker extends PackageInstaller.SessionCallback { + + // Lazily initialized + private SparseArray mActiveSessions = null; + + private final PackageInstallerCompat mInstallerCompat; + private final Callback mCallback; + + InstallSessionTracker(PackageInstallerCompat installerCompat, Callback callback) { + mInstallerCompat = installerCompat; + mCallback = callback; + } + + @Override + public void onCreated(int sessionId) { + SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId); + if (sessionInfo != null) { + mCallback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo)); + } + + mInstallerCompat.tryQueuePromiseAppIcon(sessionInfo); + } + + @Override + public void onFinished(int sessionId, boolean success) { + // For a finished session, we can't get the session info. So use the + // packageName from our local cache. + SparseArray activeSessions = getActiveSessionMap(); + PackageUserKey key = activeSessions.get(sessionId); + activeSessions.remove(sessionId); + + if (key != null && key.mPackageName != null) { + String packageName = key.mPackageName; + PackageInstallInfo info = PackageInstallInfo.fromState( + success ? STATUS_INSTALLED : STATUS_FAILED, + packageName, key.mUser); + mCallback.onPackageStateChanged(info); + + if (!success && mInstallerCompat.promiseIconAddedForId(sessionId)) { + mCallback.onSessionFailure(packageName, key.mUser); + // If it is successful, the id is removed in the the package added flow. + mInstallerCompat.removePromiseIconId(sessionId); + } + } + } + + @Override + public void onProgressChanged(int sessionId, float progress) { + SessionInfo session = mInstallerCompat.getVerifiedSessionInfo(sessionId); + if (session != null && session.getAppPackageName() != null) { + mCallback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(session)); + } + } + + @Override + public void onActiveChanged(int sessionId, boolean active) { } + + @Override + public void onBadgingChanged(int sessionId) { + SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId); + if (sessionInfo != null) { + mInstallerCompat.tryQueuePromiseAppIcon(sessionInfo); + } + } + + private SessionInfo pushSessionDisplayToLauncher(int sessionId) { + SessionInfo session = mInstallerCompat.getVerifiedSessionInfo(sessionId); + if (session != null && session.getAppPackageName() != null) { + PackageUserKey key = + new PackageUserKey(session.getAppPackageName(), getUserHandle(session)); + getActiveSessionMap().put(session.getSessionId(), key); + mCallback.onUpdateSessionDisplay(key, session); + return session; + } + return null; + } + + private SparseArray getActiveSessionMap() { + if (mActiveSessions == null) { + mActiveSessions = new SparseArray<>(); + mInstallerCompat.getActiveSessions().forEach( + (key, si) -> mActiveSessions.put(si.getSessionId(), key)); + } + return mActiveSessions; + } + + public void unregister() { + mInstallerCompat.unregister(this); + } + + public interface Callback { + + void onSessionFailure(String packageName, UserHandle user); + + void onUpdateSessionDisplay(PackageUserKey key, SessionInfo info); + + void onPackageStateChanged(PackageInstallInfo info); + + void onInstallSessionCreated(PackageInstallInfo info); + } +} diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java new file mode 100644 index 0000000000..6776ec4a2a --- /dev/null +++ b/src/com/android/launcher3/pm/PackageInstallInfo.java @@ -0,0 +1,60 @@ +/* + * 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.pm; + +import android.content.ComponentName; +import android.content.pm.PackageInstaller; +import android.os.UserHandle; + +import androidx.annotation.NonNull; + +public final class PackageInstallInfo { + + public static final int STATUS_INSTALLED = 0; + public static final int STATUS_INSTALLING = 1; + public static final int STATUS_FAILED = 2; + + public final ComponentName componentName; + public final String packageName; + public final int state; + public final int progress; + public final UserHandle user; + + private PackageInstallInfo(@NonNull PackageInstaller.SessionInfo info) { + this.state = STATUS_INSTALLING; + this.packageName = info.getAppPackageName(); + this.componentName = new ComponentName(packageName, ""); + this.progress = (int) (info.getProgress() * 100f); + this.user = PackageInstallerCompat.getUserHandle(info); + } + + public PackageInstallInfo(String packageName, int state, int progress, UserHandle user) { + this.state = state; + this.packageName = packageName; + this.componentName = new ComponentName(packageName, ""); + this.progress = progress; + this.user = user; + } + + public static PackageInstallInfo fromInstallingState(PackageInstaller.SessionInfo info) { + return new PackageInstallInfo(info); + } + + public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) { + return new PackageInstallInfo(packageName, state, 0 /* progress */, user); + } + +} diff --git a/src/com/android/launcher3/pm/PackageInstallerCompat.java b/src/com/android/launcher3/pm/PackageInstallerCompat.java new file mode 100644 index 0000000000..520c207c5f --- /dev/null +++ b/src/com/android/launcher3/pm/PackageInstallerCompat.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2014 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.pm; + +import static com.android.launcher3.Utilities.getPrefs; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.LauncherApps; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Process; +import android.os.UserHandle; +import android.text.TextUtils; + +import com.android.launcher3.SessionCommitReceiver; +import com.android.launcher3.Utilities; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.util.IntArray; +import com.android.launcher3.util.IntSet; +import com.android.launcher3.util.LooperExecutor; +import com.android.launcher3.util.PackageUserKey; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +public class PackageInstallerCompat { + + // Set of session ids of promise icons that have been added to the home screen + // as FLAG_PROMISE_NEW_INSTALLS. + protected static final String PROMISE_ICON_IDS = "promise_icon_ids"; + + private static final Object sInstanceLock = new Object(); + private static final boolean DEBUG = false; + private static PackageInstallerCompat sInstance; + private final LauncherApps mLauncherApps; + private final Context mAppContext; + private final IntSet mPromiseIconIds; + + private final PackageInstaller mInstaller; + private final HashMap mSessionVerifiedMap = new HashMap<>(); + + public PackageInstallerCompat(Context context) { + mInstaller = context.getPackageManager().getPackageInstaller(); + mAppContext = context.getApplicationContext(); + mLauncherApps = context.getSystemService(LauncherApps.class); + + mPromiseIconIds = IntSet.wrap(IntArray.fromConcatString( + getPrefs(context).getString(PROMISE_ICON_IDS, ""))); + + cleanUpPromiseIconIds(); + } + + public static PackageInstallerCompat getInstance(Context context) { + synchronized (sInstanceLock) { + if (sInstance == null) { + sInstance = new PackageInstallerCompat(context); + } + return sInstance; + } + } + + public static UserHandle getUserHandle(SessionInfo info) { + return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle(); + } + + protected void cleanUpPromiseIconIds() { + IntArray existingIds = new IntArray(); + for (SessionInfo info : getActiveSessions().values()) { + existingIds.add(info.getSessionId()); + } + IntArray idsToRemove = new IntArray(); + + for (int i = mPromiseIconIds.size() - 1; i >= 0; --i) { + if (!existingIds.contains(mPromiseIconIds.getArray().get(i))) { + idsToRemove.add(mPromiseIconIds.getArray().get(i)); + } + } + for (int i = idsToRemove.size() - 1; i >= 0; --i) { + mPromiseIconIds.getArray().removeValue(idsToRemove.get(i)); + } + } + + public HashMap getActiveSessions() { + HashMap activePackages = new HashMap<>(); + for (SessionInfo info : getAllVerifiedSessions()) { + activePackages.put( + new PackageUserKey(info.getAppPackageName(), getUserHandle(info)), info); + } + return activePackages; + } + + public SessionInfo getActiveSessionInfo(UserHandle user, String pkg) { + for (SessionInfo info : getAllVerifiedSessions()) { + boolean match = pkg.equals(info.getAppPackageName()); + if (Utilities.ATLEAST_Q && !user.equals(getUserHandle(info))) { + match = false; + } + if (match) { + return info; + } + } + return null; + } + + private void updatePromiseIconPrefs() { + getPrefs(mAppContext).edit() + .putString(PROMISE_ICON_IDS, mPromiseIconIds.getArray().toConcatString()) + .apply(); + } + + SessionInfo getVerifiedSessionInfo(int sessionId) { + return verify(mInstaller.getSessionInfo(sessionId)); + } + + private SessionInfo verify(SessionInfo sessionInfo) { + if (sessionInfo == null + || sessionInfo.getInstallerPackageName() == null + || TextUtils.isEmpty(sessionInfo.getAppPackageName())) { + return null; + } + String pkg = sessionInfo.getInstallerPackageName(); + synchronized (mSessionVerifiedMap) { + if (!mSessionVerifiedMap.containsKey(pkg)) { + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext); + boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg, + ApplicationInfo.FLAG_SYSTEM, getUserHandle(sessionInfo)) != null; + mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag); + } + } + return mSessionVerifiedMap.get(pkg) ? sessionInfo : null; + } + + public List getAllVerifiedSessions() { + List list = new ArrayList<>(Utilities.ATLEAST_Q + ? mLauncherApps.getAllPackageInstallerSessions() + : mInstaller.getAllSessions()); + Iterator it = list.iterator(); + while (it.hasNext()) { + if (verify(it.next()) == null) { + it.remove(); + } + } + return list; + } + + public boolean promiseIconAddedForId(int sessionId) { + return mPromiseIconIds.contains(sessionId); + } + + public void removePromiseIconId(int sessionId) { + if (mPromiseIconIds.contains(sessionId)) { + mPromiseIconIds.getArray().removeValue(sessionId); + updatePromiseIconPrefs(); + } + } + + /** + * Add a promise app icon to the workspace iff: + * - The settings for it are enabled + * - The user installed the app + * - There is an app icon and label (For apps with no launching activity, no icon is provided). + * - The app is not already installed + * - A promise icon for the session has not already been created + */ + void tryQueuePromiseAppIcon(PackageInstaller.SessionInfo sessionInfo) { + if (Utilities.ATLEAST_OREO && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get() + && SessionCommitReceiver.isEnabled(mAppContext) + && verify(sessionInfo) != null + && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER + && sessionInfo.getAppIcon() != null + && !TextUtils.isEmpty(sessionInfo.getAppLabel()) + && !mPromiseIconIds.contains(sessionInfo.getSessionId()) + && LauncherAppsCompat.getInstance(mAppContext).getApplicationInfo( + sessionInfo.getAppPackageName(), 0, getUserHandle(sessionInfo)) == null) { + SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo); + mPromiseIconIds.add(sessionInfo.getSessionId()); + updatePromiseIconPrefs(); + } + } + + public InstallSessionTracker registerInstallTracker( + InstallSessionTracker.Callback callback, LooperExecutor executor) { + InstallSessionTracker tracker = new InstallSessionTracker(this, callback); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + mInstaller.registerSessionCallback(tracker, executor.getHandler()); + } else { + mLauncherApps.registerPackageInstallerSessionCallback(executor, tracker); + } + return tracker; + } + + void unregister(InstallSessionTracker tracker) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + mInstaller.unregisterSessionCallback(tracker); + } else { + mLauncherApps.unregisterPackageInstallerSessionCallback(tracker); + } + } +} diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 03493a5389..455af5a449 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -25,8 +25,6 @@ import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET; import static com.android.launcher3.model.AppLaunchTracker.CONTAINER_ALL_APPS; import android.app.AlertDialog; -import android.content.ActivityNotFoundException; -import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller.SessionInfo; @@ -52,9 +50,9 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.views.FloatingIconView; import com.android.launcher3.widget.PendingAppWidgetHostView; diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index ac87148633..3d691da092 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -42,7 +42,7 @@ import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherSettings; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.tapl.Workspace; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TestViewHelpers; @@ -302,7 +302,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { Set activePackage = getOnUiThread(() -> { Set packages = new HashSet<>(); - PackageInstallerCompat.getInstance(mTargetContext).updateAndGetActiveSessionCache() + PackageInstallerCompat.getInstance(mTargetContext).getActiveSessions() .keySet().forEach(packageUserKey -> packages.add(packageUserKey.mPackageName)); return packages; }); From 52908c9adc3a27ffb90b398fa4bc97d71e9af184 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Tue, 1 Oct 2019 16:35:17 +0000 Subject: [PATCH 060/109] Revert "Revert "Revert "cache shourtcut image""" This reverts commit d13f0c5c45550bffc335f47f1a0c545df68c0584. Reason for revert: app crashes when adding widgets automatically b/141568904 Change-Id: I5b97f440716c93b1bd93c899e3e1d40e8bbd2885 --- .../launcher3/icons/cache/CachingLogic.java | 8 --- .../icons/cache/IconCacheUpdateHandler.java | 4 +- .../android/launcher3/icons/IconCache.java | 12 ---- .../launcher3/icons/LauncherIcons.java | 10 +-- .../launcher3/icons/ShortcutCachingLogic.java | 72 ------------------- .../android/launcher3/model/LoaderTask.java | 29 ++------ 6 files changed, 15 insertions(+), 120 deletions(-) delete mode 100644 src/com/android/launcher3/icons/ShortcutCachingLogic.java diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index 3aa783a14c..e40a9c2c96 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -17,7 +17,6 @@ package com.android.launcher3.icons.cache; import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageInfo; import android.os.LocaleList; import android.os.UserHandle; @@ -43,13 +42,6 @@ public interface CachingLogic { return null; } - /** - * Returns the timestamp the entry was last updated in cache. - */ - default long getLastUpdatedTime(T object, PackageInfo info) { - return info.lastUpdateTime; - } - /** * Returns true the object should be added to mem cache; otherwise returns false. */ diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java index bcdbce5e29..8224966d87 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java @@ -171,8 +171,7 @@ public class IconCacheUpdateHandler { long updateTime = c.getLong(indexLastUpdate); int version = c.getInt(indexVersion); T app = componentMap.remove(component); - if (version == info.versionCode - && updateTime == cachingLogic.getLastUpdatedTime(app, info) + if (version == info.versionCode && updateTime == info.lastUpdateTime && TextUtils.equals(c.getString(systemStateIndex), mIconCache.getIconSystemState(info.packageName))) { @@ -232,6 +231,7 @@ public class IconCacheUpdateHandler { } } + /** * A runnable that updates invalid icons and adds missing icons in the DB for the provided * LauncherActivityInfo list. Items are updated/added one at a time, so that the diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 11c7f20537..9c462606ab 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -26,7 +26,6 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ShortcutInfo; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Process; @@ -50,7 +49,6 @@ import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.icons.cache.CachingLogic; import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.model.PackageItemInfo; -import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.Preconditions; @@ -65,7 +63,6 @@ public class IconCache extends BaseIconCache { private final CachingLogic mComponentWithLabelCachingLogic; private final CachingLogic mLauncherActivityInfoCachingLogic; - private final CachingLogic mShortcutCachingLogic; private final LauncherAppsCompat mLauncherApps; private final UserManagerCompat mUserManager; @@ -79,7 +76,6 @@ public class IconCache extends BaseIconCache { inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false); mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); - mShortcutCachingLogic = new ShortcutCachingLogic(); mLauncherApps = LauncherAppsCompat.getInstance(mContext); mUserManager = UserManagerCompat.getInstance(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); @@ -177,14 +173,6 @@ public class IconCache extends BaseIconCache { getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon); } - /** - * Fill in info with the icon and label for deep shortcut. - */ - public synchronized CacheEntry getDeepShortcutTitleAndIcon(ShortcutInfo info) { - return cacheLocked(ShortcutKey.fromInfo(info).componentName, info.getUserHandle(), - () -> info, mShortcutCachingLogic, false, false); - } - /** * Fill in {@param info} with the icon and label. If the * corresponding activity is not found, it reverts to the package icon. diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index c6949afc37..adc92c46c4 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; import android.os.Process; import androidx.annotation.Nullable; @@ -32,8 +33,8 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.graphics.IconShape; -import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.model.PackageItemInfo; +import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.util.Themes; import java.util.function.Supplier; @@ -125,12 +126,13 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged, @Nullable Supplier fallbackIconProvider) { + Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext) + .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi); IconCache cache = LauncherAppState.getInstance(mContext).getIconCache(); - BaseIconCache.CacheEntry entry = cache.getDeepShortcutTitleAndIcon(shortcutInfo); final Bitmap unbadgedBitmap; - if (entry.icon != null) { - unbadgedBitmap = entry.icon; + if (unbadgedDrawable != null) { + unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0); } else { if (fallbackIconProvider != null) { // Fallback icons are already badged and with appropriate shadow diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java deleted file mode 100644 index 5d696fd6f3..0000000000 --- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.icons; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.ShortcutInfo; -import android.graphics.drawable.Drawable; -import android.os.UserHandle; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.icons.cache.CachingLogic; -import com.android.launcher3.shortcuts.DeepShortcutManager; -import com.android.launcher3.shortcuts.ShortcutKey; - -/** - * Caching logic for shortcuts. - */ -public class ShortcutCachingLogic implements CachingLogic { - - @Override - public ComponentName getComponent(ShortcutInfo info) { - return ShortcutKey.fromInfo(info).componentName; - } - - @Override - public UserHandle getUser(ShortcutInfo info) { - return info.getUserHandle(); - } - - @Override - public CharSequence getLabel(ShortcutInfo info) { - return info.getShortLabel(); - } - - @Override - public void loadIcon(Context context, ShortcutInfo info, BitmapInfo target) { - LauncherIcons li = LauncherIcons.obtain(context); - Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context) - .getShortcutIconDrawable(info, LauncherAppState.getIDP(context).fillResIconDpi); - if (unbadgedDrawable != null) { - target.icon = li.createScaledBitmapWithoutShadow(unbadgedDrawable, 0); - } - li.recycle(); - } - - @Override - public long getLastUpdatedTime(ShortcutInfo shortcutInfo, PackageInfo info) { - if (shortcutInfo == null) return info.lastUpdateTime; - return Math.max(shortcutInfo.getLastChangedTimestamp(), info.lastUpdateTime); - } - - @Override - public boolean addToMemCache() { - return false; - } -} diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 583ebee0b1..50e1d56ae0 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -63,7 +63,6 @@ import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherActivityCachingLogic; import com.android.launcher3.icons.LauncherIcons; -import com.android.launcher3.icons.ShortcutCachingLogic; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; import com.android.launcher3.logging.FileLog; import com.android.launcher3.provider.ImportDataTask; @@ -172,8 +171,7 @@ public class LoaderTask implements Runnable { TraceHelper.beginSection(TAG); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { TraceHelper.partitionSection(TAG, "step 1.1: loading workspace"); - List allShortcuts = new ArrayList<>(); - loadWorkspace(allShortcuts); + loadWorkspace(); verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace"); @@ -192,23 +190,18 @@ public class LoaderTask implements Runnable { TraceHelper.partitionSection(TAG, "step 2.1: loading all apps"); List allActivityList = loadAllApps(); - TraceHelper.partitionSection(TAG, "step 2.2: binding all apps"); + TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps"); verifyNotStopped(); mResults.bindAllApps(); verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 2.3: save app icons in icon cache"); + TraceHelper.partitionSection(TAG, "step 2.3: Update icon cache"); IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); setIgnorePackages(updateHandler); updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); - verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 2.4: save shortcuts in icon cache"); - updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), - mApp.getModel()::onPackageIconsUpdated); - // Take a break TraceHelper.partitionSection(TAG, "step 2 completed, wait for idle"); waitForIdle(); @@ -216,17 +209,12 @@ public class LoaderTask implements Runnable { // third step TraceHelper.partitionSection(TAG, "step 3.1: loading deep shortcuts"); - List allDeepShortcuts = loadDeepShortcuts(); + loadDeepShortcuts(); verifyNotStopped(); TraceHelper.partitionSection(TAG, "step 3.2: bind deep shortcuts"); mResults.bindDeepShortcuts(); - verifyNotStopped(); - TraceHelper.partitionSection(TAG, "step 3.3: save deep shortcuts in icon cache"); - updateHandler.updateIcons(allDeepShortcuts, - new ShortcutCachingLogic(), (pkgs, user) -> { }); - // Take a break TraceHelper.partitionSection(TAG, "step 3 completed, wait for idle"); waitForIdle(); @@ -241,6 +229,7 @@ public class LoaderTask implements Runnable { mResults.bindWidgets(); verifyNotStopped(); + TraceHelper.partitionSection(TAG, "step 4.3: save widgets in icon cache"); updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic( mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); @@ -262,7 +251,7 @@ public class LoaderTask implements Runnable { this.notify(); } - private void loadWorkspace(List allDeepShortcuts) { + private void loadWorkspace() { final Context context = mApp.getContext(); final ContentResolver contentResolver = context.getContentResolver(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); @@ -515,7 +504,6 @@ public class LoaderTask implements Runnable { info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED; } intent = info.intent; - allDeepShortcuts.add(pinnedShortcut); } else { // Create a shortcut info in disabled mode for now. info = c.loadSimpleWorkspaceItem(); @@ -864,8 +852,7 @@ public class LoaderTask implements Runnable { return allActivityList; } - private List loadDeepShortcuts() { - List allShortcuts = new ArrayList<>(); + private void loadDeepShortcuts() { mBgDataModel.deepShortcutMap.clear(); mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission(); if (mBgDataModel.hasShortcutHostPermission) { @@ -873,12 +860,10 @@ public class LoaderTask implements Runnable { if (mUserManager.isUserUnlocked(user)) { List shortcuts = mShortcutManager.queryForAllShortcuts(user); - allShortcuts.addAll(shortcuts); mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts); } } } - return allShortcuts; } public static boolean isValidProvider(AppWidgetProviderInfo provider) { From c9654eb09158a9878d7ff8fc9e588ec2d4903318 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 1 Oct 2019 10:03:14 -0700 Subject: [PATCH 061/109] Don't allow scrolling RecentsView outside navbar during quickswitch Once the inputProxy (OverviewInputConsumer) was enabled, it was never disabled. And while it was enabled, touches above the nav bar would go through to launcher, allowing you to scroll RecentsView (for example) during quick switch transitions. This breaks some assumptions, since it doesn't go through our normal shared swipe state logic that cancels the animation, updates the new end target (e.g. NEW_TASK vs LAST_TASK), etc. Thus, if you tried returning to LAST_TASK via this route, we would end up starting it as a new activity instead of resuming the existing one, causing a flicker (I guess because that TaskView is hidden). Test: - Swipe up from task A to home (to enable input proxy) - Open A - Swipe to B, and during transition scroll back to A from the center of the screen Before, this caused a flicker, now the last scroll is ignored. TODO: we should increase the nav region during quick switch to make it easier to continue scrolling Bug: 136829198 Bug: 138620399 Change-Id: I5ffb53743b728e1909066c5dd18cc9308aff2c7e --- .../quickstep/RecentsAnimationWrapper.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java index e51ba631bf..c4d3fa03aa 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java @@ -19,6 +19,8 @@ import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; +import android.os.SystemClock; +import android.util.Log; import android.view.InputEvent; import android.view.KeyEvent; import android.view.MotionEvent; @@ -38,6 +40,8 @@ import java.util.function.Supplier; */ public class RecentsAnimationWrapper { + private static final String TAG = "RecentsAnimationWrapper"; + // A list of callbacks to run when we receive the recents animation target. There are different // than the state callbacks as these run on the current worker thread. private final ArrayList mCallbacks = new ArrayList<>(); @@ -125,6 +129,7 @@ public class RecentsAnimationWrapper { boolean sendUserLeaveHint) { SwipeAnimationTargetSet controller = targetSet; targetSet = null; + disableInputProxy(); if (controller != null) { controller.finishController(toRecents, onFinishComplete, sendUserLeaveHint); } @@ -153,6 +158,16 @@ public class RecentsAnimationWrapper { mInputConsumerController.setInputListener(this::onInputConsumerEvent); } + private void disableInputProxy() { + if (mInputConsumer != null && mTouchInProgress) { + long now = SystemClock.uptimeMillis(); + MotionEvent dummyCancel = MotionEvent.obtain(now, now, ACTION_CANCEL, 0, 0, 0); + mInputConsumer.onMotionEvent(dummyCancel); + dummyCancel.recycle(); + } + mInputConsumerController.setInputListener(null); + } + private boolean onInputConsumerEvent(InputEvent ev) { if (ev instanceof MotionEvent) { onInputConsumerMotionEvent((MotionEvent) ev); @@ -168,6 +183,18 @@ public class RecentsAnimationWrapper { private boolean onInputConsumerMotionEvent(MotionEvent ev) { int action = ev.getAction(); + + // Just to be safe, verify that ACTION_DOWN comes before any other action, + // and ignore any ACTION_DOWN after the first one (though that should not happen). + if (!mTouchInProgress && action != ACTION_DOWN) { + Log.w(TAG, "Received non-down motion before down motion: " + action); + return false; + } + if (mTouchInProgress && action == ACTION_DOWN) { + Log.w(TAG, "Received down motion while touch was already in progress"); + return false; + } + if (action == ACTION_DOWN) { mTouchInProgress = true; if (mInputConsumer == null) { From 1f3a847011784a00d415273f6ca61f26172b0699 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Fri, 6 Sep 2019 11:25:08 -0700 Subject: [PATCH 062/109] App title in Widget list shouldn't be actionable by a11y methods Bug:139913027 Test:Manual Change-Id: I2a5d5551d09ee2bc96444164ed77225a3b4a829a (cherry picked from commit d3720c210b2b0fbb508bd9f16b88b10e4b001149) --- src/com/android/launcher3/LauncherSettings.java | 4 ++++ src/com/android/launcher3/model/PackageItemInfo.java | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 242e099b23..c509680981 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -58,6 +58,10 @@ public class LauncherSettings { */ public static final String ITEM_TYPE = "itemType"; + /** + * The gesture is a package + */ + public static final int ITEM_TYPE_NON_ACTIONABLE = -1; /** * The gesture is an application */ diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java index 741be66a03..3ef48cd8fd 100644 --- a/src/com/android/launcher3/model/PackageItemInfo.java +++ b/src/com/android/launcher3/model/PackageItemInfo.java @@ -17,6 +17,7 @@ package com.android.launcher3.model; import com.android.launcher3.ItemInfoWithIcon; +import com.android.launcher3.LauncherSettings; /** * Represents a {@link Package} in the widget tray section. @@ -30,10 +31,12 @@ public class PackageItemInfo extends ItemInfoWithIcon { public PackageItemInfo(String packageName) { this.packageName = packageName; + this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE; } public PackageItemInfo(PackageItemInfo copy) { this.packageName = copy.packageName; + this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE; } @Override From 542b7df7fd280c8596ce4db957c6339c1c3ac085 Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 27 Sep 2019 18:44:04 -0700 Subject: [PATCH 063/109] Waiting for Launcher model load in out-of-proc tests. Not doing this seems to have caused flakes. Bug: 141770616 Change-Id: Ia9caf20e4a2d93298adf4249ca815ad79bced802 --- .../quickstep/QuickstepTestInformationHandler.java | 11 +++++------ .../launcher3/testing/TestInformationHandler.java | 8 +++++++- .../launcher3/ui/DefaultLayoutProviderTest.java | 3 --- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index 9a01c546af..c4f375a124 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -39,12 +39,6 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { return response; } - case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: { - response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, - TouchInteractionService.isInitialized()); - return response; - } - case TestProtocol.REQUEST_HOTSEAT_TOP: { if (mLauncher == null) return null; @@ -91,4 +85,9 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { observer.onDestroy(); } } + + @Override + protected boolean isLauncherInitialized() { + return super.isLauncherInitialized() && TouchInteractionService.isInitialized(); + } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index aa6c47149f..6f53544c2e 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -29,6 +29,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsStore; @@ -91,7 +92,7 @@ public class TestInformationHandler implements ResourceBasedOverride { } case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: { - response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true); + response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, isLauncherInitialized()); break; } @@ -176,4 +177,9 @@ public class TestInformationHandler implements ResourceBasedOverride { } return response; } + + protected boolean isLauncherInitialized() { + final LauncherModel model = LauncherAppState.getInstance(mContext).getModel(); + return model.getCallback() == null || model.isModelLoaded(); + } } diff --git a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java index 3d4e17bf5c..1d89d6edcb 100644 --- a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java +++ b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java @@ -73,7 +73,6 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); mLauncher.getWorkspace().getHotseatAppIcon(getSettingsApp().getLabel().toString()); } @@ -89,7 +88,6 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); // Verify widget present assertTrue("Widget is not present", @@ -106,7 +104,6 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); mLauncher.getWorkspace().getHotseatFolder("Folder: Copy"); } From 7371e4da6846e532592ac14f3a9ab12576a29a1c Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 27 Sep 2019 18:44:04 -0700 Subject: [PATCH 064/109] Waiting for Launcher model load in out-of-proc tests. Not doing this seems to have caused flakes. Bug: 141770616 Change-Id: Ia9caf20e4a2d93298adf4249ca815ad79bced802 Merged-in: Ia9caf20e4a2d93298adf4249ca815ad79bced802 --- .../quickstep/QuickstepTestInformationHandler.java | 11 +++++------ .../launcher3/testing/TestInformationHandler.java | 8 +++++++- .../launcher3/ui/DefaultLayoutProviderTest.java | 3 --- .../android/launcher3/ui/widget/BindWidgetTest.java | 1 - 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index da4642636d..2864c46406 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -36,12 +36,6 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { return response; } - case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: { - response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, - TouchInteractionService.isInitialized()); - return response; - } - case TestProtocol.REQUEST_HOTSEAT_TOP: { if (mLauncher == null) return null; @@ -80,4 +74,9 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { return super.call(method); } + + @Override + protected boolean isLauncherInitialized() { + return super.isLauncherInitialized() && TouchInteractionService.isInitialized(); + } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 790a2e8448..9965572bde 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -27,6 +27,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherState; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; @@ -82,7 +83,7 @@ public class TestInformationHandler implements ResourceBasedOverride { } case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: { - response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true); + response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, isLauncherInitialized()); break; } @@ -152,4 +153,9 @@ public class TestInformationHandler implements ResourceBasedOverride { } return response; } + + protected boolean isLauncherInitialized() { + final LauncherModel model = LauncherAppState.getInstance(mContext).getModel(); + return model.getCallback() == null || model.isModelLoaded(); + } } \ No newline at end of file diff --git a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java index a76b4a4886..ff21880d0e 100644 --- a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java +++ b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java @@ -73,7 +73,6 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); mLauncher.getWorkspace().getHotseatAppIcon(getSettingsApp().getLabel().toString()); } @@ -89,7 +88,6 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); // Verify widget present assertTrue("Widget is not present", @@ -106,7 +104,6 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); mLauncher.getWorkspace().getHotseatFolder("Folder: Copy"); } diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index e6348d9c02..f42bf1f3ce 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -271,7 +271,6 @@ public class BindWidgetTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); } private void verifyWidgetPresent(LauncherAppWidgetProviderInfo info) { From e84c5b82be573c44b144f255e6a6b82c8ca16491 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 26 Sep 2019 17:05:31 -0700 Subject: [PATCH 065/109] Unifying activity tracker callback > Using a common class for both Launcher and RecentsActivity > Removing static refenrece to LauncherModel and using a common pattern for tracking activities Bug: 141376165 Bug: 137568159 Change-Id: Ic1897abe6913ec78e25725118eedf5b468d5ec70 --- .../FallbackActivityControllerHelper.java | 5 +- .../LauncherActivityControllerHelper.java | 2 +- .../quickstep/OverviewCommandHelper.java | 4 +- .../launcher3/LauncherInitListenerEx.java | 2 +- .../android/quickstep/BaseSwipeUpHandler.java | 2 +- .../FallbackActivityControllerHelper.java | 5 +- .../LauncherActivityControllerHelper.java | 8 +- .../quickstep/OverviewCommandHelper.java | 4 +- .../android/quickstep/RecentsActivity.java | 2 +- .../FallbackNoButtonInputConsumer.java | 2 +- .../launcher3/LauncherInitListener.java | 27 +--- .../quickstep/ActivityControlHelper.java | 14 +- .../quickstep/BaseRecentsActivity.java | 8 +- .../quickstep/RecentsActivityTracker.java | 130 ---------------- .../quickstep/util/ActivityInitListener.java | 60 ++++++++ src/com/android/launcher3/Launcher.java | 11 +- .../launcher3/allapps/DiscoveryBounce.java | 4 +- .../launcher3/dragndrop/AddItemActivity.java | 3 +- .../dragndrop/BaseItemDragListener.java | 9 +- .../states/InternalStateHandler.java | 145 ------------------ .../launcher3/states/RotationHelper.java | 5 +- .../testing/TestInformationHandler.java | 3 +- .../launcher3/util/ActivityTracker.java | 131 ++++++++++++++++ .../launcher3}/util/ObjectWrapper.java | 2 +- 24 files changed, 239 insertions(+), 349 deletions(-) delete mode 100644 quickstep/src/com/android/quickstep/RecentsActivityTracker.java create mode 100644 quickstep/src/com/android/quickstep/util/ActivityInitListener.java delete mode 100644 src/com/android/launcher3/states/InternalStateHandler.java create mode 100644 src/com/android/launcher3/util/ActivityTracker.java rename {quickstep/recents_ui_overrides/src/com/android/quickstep => src/com/android/launcher3}/util/ObjectWrapper.java (96%) diff --git a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java index 057b48bb2b..49945263a4 100644 --- a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java +++ b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java @@ -26,6 +26,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.IconRecentsView; @@ -85,13 +86,13 @@ public final class FallbackActivityControllerHelper extends @Override public ActivityInitListener createActivityInitListener( BiPredicate onInitListener) { - return new RecentsActivityTracker(onInitListener); + return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER); } @Nullable @Override public RecentsActivity getCreatedActivity() { - return RecentsActivityTracker.getCurrentActivity(); + return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); } @Nullable diff --git a/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java b/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java index b0d9cda6bc..8993b67005 100644 --- a/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -55,7 +55,7 @@ public final class LauncherActivityControllerHelper extends GoActivityControlHel } @Override - public ActivityInitListener createActivityInitListener( + public LauncherInitListener createActivityInitListener( BiPredicate onInitListener) { return new LauncherInitListener(onInitListener); } diff --git a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 216972cba2..9c409ccca5 100644 --- a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -27,8 +27,8 @@ import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.AppToOverviewAnimationProvider.AppToOverviewAnimationListener; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.views.IconRecentsView; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.LatencyTrackerCompat; @@ -104,7 +104,7 @@ public class OverviewCommandHelper { private final long mToggleClickedTime = SystemClock.uptimeMillis(); private boolean mUserEventLogged; - private ActivityInitListener mListener; + private ActivityInitListener mListener; public RecentsActivityCommand() { mHelper = mOverviewComponentObserver.getActivityControlHelper(); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java index c5c4add6b2..76050d57bd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java @@ -27,7 +27,7 @@ public class LauncherInitListenerEx extends LauncherInitListener { } @Override - protected boolean init(Launcher launcher, boolean alreadyOnHome) { + public boolean init(Launcher launcher, boolean alreadyOnHome) { PredictionUiStateManager.INSTANCE.get(launcher).switchClient(Client.OVERVIEW); return super.init(launcher, alreadyOnHome); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index 7196f7c6f3..d524b5d25c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -57,10 +57,10 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.views.FloatingIconView; -import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.InputConsumer; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.ClipAnimationHelper; import com.android.quickstep.util.ClipAnimationHelper.TransformParams; import com.android.quickstep.util.RectFSpringAnim; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java index 8c5a78823a..33180a9654 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java @@ -35,6 +35,7 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.fallback.FallbackRecentsView; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.RecentsView; @@ -177,13 +178,13 @@ public final class FallbackActivityControllerHelper implements @Override public ActivityInitListener createActivityInitListener( BiPredicate onInitListener) { - return new RecentsActivityTracker(onInitListener); + return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER); } @Nullable @Override public RecentsActivity getCreatedActivity() { - return RecentsActivityTracker.getCurrentActivity(); + return BaseRecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); } @Nullable diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 0d3d119594..e7005a62ef 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -50,7 +50,6 @@ import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherInitListenerEx; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; @@ -61,6 +60,7 @@ import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.SysUINavigationMode.Mode; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.views.LauncherRecentsView; @@ -404,11 +404,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe @Nullable @Override public Launcher getCreatedActivity() { - LauncherAppState app = LauncherAppState.getInstanceNoCreate(); - if (app == null) { - return null; - } - return (Launcher) app.getModel().getCallback(); + return Launcher.ACTIVITY_TRACKER.getCreatedActivity(); } @Nullable 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 6a06de9569..6df9ce5736 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -25,14 +25,12 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.SystemClock; -import android.util.Log; import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.logging.UserEventDispatcher; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.quickstep.ActivityControlHelper.ActivityInitListener; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.ActivityManagerWrapper; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java index bebd45daa2..4a9aa2d9a8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java @@ -38,11 +38,11 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAnimationRunner; import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.fallback.RecentsRootView; import com.android.quickstep.util.ClipAnimationHelper; -import com.android.quickstep.util.ObjectWrapper; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityOptionsCompat; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index e0ff8afe65..6275d21dc0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -38,6 +38,7 @@ import android.os.Bundle; import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.util.ObjectWrapper; import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseSwipeUpHandler; @@ -47,7 +48,6 @@ import com.android.quickstep.RecentsActivity; import com.android.quickstep.RecentsModel; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.fallback.FallbackRecentsView; -import com.android.quickstep.util.ObjectWrapper; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.SwipeAnimationTargetSet; import com.android.quickstep.views.TaskView; diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index 272d1175b1..663b1252d3 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -19,29 +19,25 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.os.Build; -import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; -import com.android.launcher3.states.InternalStateHandler; -import com.android.quickstep.ActivityControlHelper.ActivityInitListener; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationProvider; import java.util.function.BiPredicate; @TargetApi(Build.VERSION_CODES.P) -public class LauncherInitListener extends InternalStateHandler implements ActivityInitListener { - - private final BiPredicate mOnInitListener; +public class LauncherInitListener extends ActivityInitListener { private RemoteAnimationProvider mRemoteAnimationProvider; public LauncherInitListener(BiPredicate onInitListener) { - mOnInitListener = onInitListener; + super(onInitListener, Launcher.ACTIVITY_TRACKER); } @Override - protected boolean init(Launcher launcher, boolean alreadyOnHome) { + public boolean init(Launcher launcher, boolean alreadyOnHome) { if (mRemoteAnimationProvider != null) { QuickstepAppTransitionManagerImpl appTransitionManager = (QuickstepAppTransitionManagerImpl) launcher.getAppTransitionManager(); @@ -63,28 +59,19 @@ public class LauncherInitListener extends InternalStateHandler implements Activi }, cancellationSignal); } launcher.deferOverlayCallbacksUntilNextResumeOrStop(); - return mOnInitListener.test(launcher, alreadyOnHome); - } - - @Override - public void register() { - initWhenReady(); + return super.init(launcher, alreadyOnHome); } @Override public void unregister() { mRemoteAnimationProvider = null; - clearReference(); + super.unregister(); } @Override public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, Context context, Handler handler, long duration) { mRemoteAnimationProvider = animProvider; - - register(); - - Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle(); - context.startActivity(addToIntent(new Intent((intent))), options); + super.registerAndStartActivity(intent, animProvider, context, handler, duration); } } diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 609fb26d40..2d4b136139 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -17,12 +17,10 @@ package com.android.quickstep; import android.annotation.TargetApi; import android.content.Context; -import android.content.Intent; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Build; -import android.os.Handler; import android.view.MotionEvent; import android.view.View; import android.view.animation.Interpolator; @@ -34,7 +32,7 @@ import androidx.annotation.UiThread; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -99,16 +97,6 @@ public interface ActivityControlHelper { default void closeOverlay() { } - interface ActivityInitListener { - - void register(); - - void unregister(); - - void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, - Context context, Handler handler, long duration); - } - interface AnimationFactory { enum ShelfAnimState { diff --git a/quickstep/src/com/android/quickstep/BaseRecentsActivity.java b/quickstep/src/com/android/quickstep/BaseRecentsActivity.java index 1ac7ed4a3c..71833ad418 100644 --- a/quickstep/src/com/android/quickstep/BaseRecentsActivity.java +++ b/quickstep/src/com/android/quickstep/BaseRecentsActivity.java @@ -28,6 +28,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.launcher3.uioverrides.UiFactory; +import com.android.launcher3.util.ActivityTracker; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; @@ -43,6 +44,7 @@ import java.io.PrintWriter; */ public abstract class BaseRecentsActivity extends BaseDraggingActivity { + public static ActivityTracker ACTIVITY_TRACKER = new ActivityTracker<>(); private Configuration mOldConfig; @Override @@ -55,7 +57,7 @@ public abstract class BaseRecentsActivity extends BaseDraggingActivity { getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW, Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)); - RecentsActivityTracker.onRecentsActivityCreate(this); + ACTIVITY_TRACKER.handleCreate((RecentsActivity) this); } /** @@ -132,13 +134,13 @@ public abstract class BaseRecentsActivity extends BaseDraggingActivity { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - RecentsActivityTracker.onRecentsActivityNewIntent(this); + ACTIVITY_TRACKER.handleNewIntent(this, intent); } @Override protected void onDestroy() { super.onDestroy(); - RecentsActivityTracker.onRecentsActivityDestroy(this); + ACTIVITY_TRACKER.onActivityDestroyed(this); } @Override diff --git a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java deleted file mode 100644 index 4d1d9ef8a7..0000000000 --- a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.quickstep; - -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; - -import com.android.quickstep.ActivityControlHelper.ActivityInitListener; -import com.android.quickstep.util.RemoteAnimationProvider; - -import java.lang.ref.WeakReference; -import java.util.function.BiPredicate; - -/** - * Utility class to track create/destroy for some {@link BaseRecentsActivity}. - */ -@TargetApi(Build.VERSION_CODES.P) -public class RecentsActivityTracker implements ActivityInitListener { - - private static WeakReference sCurrentActivity = - new WeakReference<>(null); - private static final Scheduler sScheduler = new Scheduler(); - - private final BiPredicate mOnInitListener; - - public RecentsActivityTracker(BiPredicate onInitListener) { - mOnInitListener = onInitListener; - } - - @Override - public void register() { - sScheduler.schedule(this); - } - - @Override - public void unregister() { - sScheduler.clearReference(this); - } - - private boolean init(T activity, boolean visible) { - return mOnInitListener.test(activity, visible); - } - - public static T getCurrentActivity() { - return (T) sCurrentActivity.get(); - } - - @Override - public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, - Context context, Handler handler, long duration) { - register(); - - Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle(); - context.startActivity(intent, options); - } - - public static void onRecentsActivityCreate(BaseRecentsActivity activity) { - sCurrentActivity = new WeakReference<>(activity); - sScheduler.initIfPending(activity, false); - } - - - public static void onRecentsActivityNewIntent(BaseRecentsActivity activity) { - sScheduler.initIfPending(activity, activity.isStarted()); - } - - public static void onRecentsActivityDestroy(BaseRecentsActivity activity) { - if (sCurrentActivity.get() == activity) { - sCurrentActivity.clear(); - } - } - - - private static class Scheduler implements Runnable { - - private WeakReference mPendingTracker = new WeakReference<>(null); - - public synchronized void schedule(RecentsActivityTracker tracker) { - mPendingTracker = new WeakReference<>(tracker); - MAIN_EXECUTOR.execute(this); - } - - @Override - public void run() { - BaseRecentsActivity activity = sCurrentActivity.get(); - if (activity != null) { - initIfPending(activity, activity.isStarted()); - } - } - - public synchronized boolean initIfPending(BaseRecentsActivity activity, - boolean alreadyOnHome) { - RecentsActivityTracker tracker = mPendingTracker.get(); - if (tracker != null) { - if (!tracker.init(activity, alreadyOnHome)) { - mPendingTracker.clear(); - } - return true; - } - return false; - } - - public synchronized boolean clearReference(RecentsActivityTracker tracker) { - if (mPendingTracker.get() == tracker) { - mPendingTracker.clear(); - return true; - } - return false; - } - } -} diff --git a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java new file mode 100644 index 0000000000..fe37d609b4 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java @@ -0,0 +1,60 @@ +/* + * 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.quickstep.util; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; + +import com.android.launcher3.BaseActivity; +import com.android.launcher3.util.ActivityTracker; +import com.android.launcher3.util.ActivityTracker.SchedulerCallback; + +import java.util.function.BiPredicate; + +public class ActivityInitListener implements SchedulerCallback { + + private final BiPredicate mOnInitListener; + private final ActivityTracker mActivityTracker; + + public ActivityInitListener(BiPredicate onInitListener, + ActivityTracker tracker) { + mOnInitListener = onInitListener; + mActivityTracker = tracker; + } + + @Override + public boolean init(T activity, boolean alreadyOnHome) { + return mOnInitListener.test(activity, alreadyOnHome); + } + + public void register() { + mActivityTracker.schedule(this); + } + + public void unregister() { + mActivityTracker.clearReference(this); + } + + public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, + Context context, Handler handler, long duration) { + register(); + + Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle(); + context.startActivity(addToIntent(new Intent((intent))), options); + } +} diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 4f8b20e0b4..9326e95dea 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -113,7 +113,6 @@ import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.qsb.QsbContainerView; -import com.android.launcher3.states.InternalStateHandler; import com.android.launcher3.states.RotationHelper; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.uioverrides.DejankBinderTracker; @@ -124,6 +123,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ActivityResultInfo; +import com.android.launcher3.util.ActivityTracker; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.ItemInfoMatcher; @@ -176,6 +176,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, Callbacks, LauncherProviderChangeListener, UserEventDelegate, InvariantDeviceProfile.OnIDPChangeListener, PluginListener { public static final String TAG = "Launcher"; + + public static final ActivityTracker ACTIVITY_TRACKER = new ActivityTracker<>(); + static final boolean LOGD = false; static final boolean DEBUG_STRICT_MODE = false; @@ -359,7 +362,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, mAppTransitionManager = LauncherAppTransitionManager.newInstance(this); - boolean internalStateHandled = InternalStateHandler.handleCreate(this, getIntent()); + boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this); if (internalStateHandled) { if (savedInstanceState != null) { // InternalStateHandler has already set the appropriate state. @@ -1444,8 +1447,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL) && AbstractFloatingView.getTopOpenView(this) == null; boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); - boolean internalStateHandled = InternalStateHandler - .handleNewIntent(this, intent, isStarted()); + boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this, intent); if (isActionMain) { if (!internalStateHandled) { @@ -1535,6 +1537,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, @Override public void onDestroy() { super.onDestroy(); + ACTIVITY_TRACKER.onActivityDestroyed(this); unregisterReceiver(mScreenOffReceiver); mWorkspace.removeFolderListeners(); diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java index 8c596269de..dc2f7bdc9e 100644 --- a/src/com/android/launcher3/allapps/DiscoveryBounce.java +++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java @@ -31,12 +31,10 @@ import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager; import com.android.launcher3.LauncherStateManager.StateListener; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.compat.UserManagerCompat; -import com.android.launcher3.states.InternalStateHandler; /** * Abstract base class of floating view responsible for showing discovery bounce animation @@ -181,7 +179,7 @@ public class DiscoveryBounce extends AbstractFloatingView { if (withDelay) { new Handler().postDelayed(() -> showForOverviewIfNeeded(launcher, false), DELAY_MS); return; - } else if (InternalStateHandler.hasPending() + } else if (Launcher.ACTIVITY_TRACKER.hasPending() || AbstractFloatingView.getTopOpenView(launcher) != null) { // TODO: Move these checks to the top and call this method after invalidate handler. return; diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 9fb10905f8..b8981b6a3c 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -45,6 +45,7 @@ import android.view.View.OnTouchListener; import com.android.launcher3.BaseActivity; import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetHost; import com.android.launcher3.LauncherAppWidgetProviderInfo; @@ -176,7 +177,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener .setPackage(getPackageName()) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); - listener.initWhenReady(); + Launcher.ACTIVITY_TRACKER.schedule(listener); startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out).toBundle()); mFinishOnPause = true; diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java index 1b08723f63..75693c63d0 100644 --- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java @@ -36,8 +36,7 @@ import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.Launcher; import com.android.launcher3.R; -import com.android.launcher3.states.InternalStateHandler; -import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.util.ActivityTracker.SchedulerCallback; import com.android.launcher3.widget.PendingItemDragHelper; import java.util.UUID; @@ -45,8 +44,8 @@ import java.util.UUID; /** * {@link DragSource} for handling drop from a different window. */ -public abstract class BaseItemDragListener extends InternalStateHandler implements - View.OnDragListener, DragSource, DragOptions.PreDragCondition { +public abstract class BaseItemDragListener implements View.OnDragListener, DragSource, + DragOptions.PreDragCondition, SchedulerCallback { private static final String TAG = "BaseItemDragListener"; @@ -165,7 +164,7 @@ public abstract class BaseItemDragListener extends InternalStateHandler implemen } protected void postCleanup() { - clearReference(); + Launcher.ACTIVITY_TRACKER.clearReference(this); if (mLauncher != null) { // Remove any drag params from the launcher intent since the drag operation is complete. Intent newIntent = new Intent(mLauncher.getIntent()); diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java deleted file mode 100644 index a23cd6d2e3..0000000000 --- a/src/com/android/launcher3/states/InternalStateHandler.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2017 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.states; - -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; - -import android.content.Intent; -import android.os.Binder; -import android.os.Bundle; -import android.os.IBinder; - -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.model.BgDataModel.Callbacks; - -import java.lang.ref.WeakReference; - -/** - * Utility class to sending state handling logic to Launcher from within the same process. - * - * Extending {@link Binder} ensures that the platform maintains a single instance of each object - * which allows this object to safely navigate the system process. - */ -public abstract class InternalStateHandler extends Binder { - - public static final String EXTRA_STATE_HANDLER = "launcher.state_handler"; - - private static final Scheduler sScheduler = new Scheduler(); - - /** - * Initializes the handler when the launcher is ready. - * @return true if the handler wants to stay alive. - */ - protected abstract boolean init(Launcher launcher, boolean alreadyOnHome); - - public final Intent addToIntent(Intent intent) { - Bundle extras = new Bundle(); - extras.putBinder(EXTRA_STATE_HANDLER, this); - intent.putExtras(extras); - return intent; - } - - public final void initWhenReady() { - sScheduler.schedule(this); - } - - public boolean clearReference() { - return sScheduler.clearReference(this); - } - - public static boolean hasPending() { - return sScheduler.hasPending(); - } - - public static boolean handleCreate(Launcher launcher, Intent intent) { - return handleIntent(launcher, intent, false, false); - } - - public static boolean handleNewIntent(Launcher launcher, Intent intent, boolean alreadyOnHome) { - return handleIntent(launcher, intent, alreadyOnHome, true); - } - - private static boolean handleIntent( - Launcher launcher, Intent intent, boolean alreadyOnHome, boolean explicitIntent) { - boolean result = false; - if (intent != null && intent.getExtras() != null) { - IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER); - if (stateBinder instanceof InternalStateHandler) { - InternalStateHandler handler = (InternalStateHandler) stateBinder; - if (!handler.init(launcher, alreadyOnHome)) { - intent.getExtras().remove(EXTRA_STATE_HANDLER); - } - result = true; - } - } - if (!result && !explicitIntent) { - result = sScheduler.initIfPending(launcher, alreadyOnHome); - } - return result; - } - - private static class Scheduler implements Runnable { - - private WeakReference mPendingHandler = new WeakReference<>(null); - - public void schedule(InternalStateHandler handler) { - synchronized (this) { - mPendingHandler = new WeakReference<>(handler); - } - MAIN_EXECUTOR.execute(this); - } - - @Override - public void run() { - LauncherAppState app = LauncherAppState.getInstanceNoCreate(); - if (app == null) { - return; - } - Callbacks cb = app.getModel().getCallback(); - if (!(cb instanceof Launcher)) { - return; - } - Launcher launcher = (Launcher) cb; - initIfPending(launcher, launcher.isStarted()); - } - - public boolean initIfPending(Launcher launcher, boolean alreadyOnHome) { - InternalStateHandler pendingHandler = mPendingHandler.get(); - if (pendingHandler != null) { - if (!pendingHandler.init(launcher, alreadyOnHome)) { - clearReference(pendingHandler); - } - return true; - } - return false; - } - - public boolean clearReference(InternalStateHandler handler) { - synchronized (this) { - if (mPendingHandler.get() == handler) { - mPendingHandler.clear(); - return true; - } - return false; - } - } - - public boolean hasPending() { - return mPendingHandler.get() != null; - } - } -} \ No newline at end of file diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java index abf90e22c8..852928b416 100644 --- a/src/com/android/launcher3/states/RotationHelper.java +++ b/src/com/android/launcher3/states/RotationHelper.java @@ -24,7 +24,6 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Resources; import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; import com.android.launcher3.Launcher; import com.android.launcher3.R; @@ -59,7 +58,9 @@ public class RotationHelper implements OnSharedPreferenceChangeListener { private boolean mAutoRotateEnabled; /** - * Rotation request made by {@link InternalStateHandler}. This supersedes any other request. + * Rotation request made by + * {@link com.android.launcher3.util.ActivityTracker.SchedulerCallback}. + * This supersedes any other request. */ private int mStateHandlerRequest = REQUEST_NONE; /** diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index a71a53b927..619293bd84 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -56,8 +56,7 @@ public class TestInformationHandler implements ResourceBasedOverride { mDeviceProfile = InvariantDeviceProfile.INSTANCE. get(context).getDeviceProfile(context); mLauncherAppState = LauncherAppState.getInstanceNoCreate(); - mLauncher = mLauncherAppState != null ? - (Launcher) mLauncherAppState.getModel().getCallback() : null; + mLauncher = Launcher.ACTIVITY_TRACKER.getCreatedActivity(); } public Bundle call(String method) { diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java new file mode 100644 index 0000000000..e85a4e8058 --- /dev/null +++ b/src/com/android/launcher3/util/ActivityTracker.java @@ -0,0 +1,131 @@ +/* + * 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 static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; + +import androidx.annotation.Nullable; + +import com.android.launcher3.BaseActivity; + +import java.lang.ref.WeakReference; + +/** + * Helper class to statically track activity creation + */ +public final class ActivityTracker implements Runnable { + + private WeakReference mCurrentActivity = new WeakReference<>(null); + private WeakReference> mPendingCallback = new WeakReference<>(null); + + private static final String EXTRA_SCHEDULER_CALLBACK = "launcher.scheduler_callback"; + + @Nullable + public R getCreatedActivity() { + return (R) mCurrentActivity.get(); + } + + public void onActivityDestroyed(T activity) { + if (mCurrentActivity.get() == activity) { + mCurrentActivity.clear(); + } + } + + public void schedule(SchedulerCallback callback) { + synchronized (this) { + mPendingCallback = new WeakReference<>((SchedulerCallback) callback); + } + MAIN_EXECUTOR.execute(this); + } + + @Override + public void run() { + T activity = mCurrentActivity.get(); + if (activity != null) { + initIfPending(activity, activity.isStarted()); + } + } + + public boolean initIfPending(T activity, boolean alreadyOnHome) { + SchedulerCallback pendingCallback = mPendingCallback.get(); + if (pendingCallback != null) { + if (!pendingCallback.init(activity, alreadyOnHome)) { + clearReference(pendingCallback); + } + return true; + } + return false; + } + + public boolean clearReference(SchedulerCallback handler) { + synchronized (this) { + if (mPendingCallback.get() == handler) { + mPendingCallback.clear(); + return true; + } + return false; + } + } + + public boolean hasPending() { + return mPendingCallback.get() != null; + } + + public boolean handleCreate(T activity) { + mCurrentActivity = new WeakReference<>(activity); + return handleIntent(activity, activity.getIntent(), false, false); + } + + public boolean handleNewIntent(T activity, Intent intent) { + return handleIntent(activity, intent, activity.isStarted(), true); + } + + private boolean handleIntent( + T activity, Intent intent, boolean alreadyOnHome, boolean explicitIntent) { + boolean result = false; + if (intent != null && intent.getExtras() != null) { + IBinder stateBinder = intent.getExtras().getBinder(EXTRA_SCHEDULER_CALLBACK); + if (stateBinder instanceof ObjectWrapper) { + SchedulerCallback handler = + ((ObjectWrapper) stateBinder).get(); + if (!handler.init(activity, alreadyOnHome)) { + intent.getExtras().remove(EXTRA_SCHEDULER_CALLBACK); + } + result = true; + } + } + if (!result && !explicitIntent) { + result = initIfPending(activity, alreadyOnHome); + } + return result; + } + + public interface SchedulerCallback { + + boolean init(T activity, boolean alreadyOnHome); + + default Intent addToIntent(Intent intent) { + Bundle extras = new Bundle(); + extras.putBinder(EXTRA_SCHEDULER_CALLBACK, ObjectWrapper.wrap(this)); + intent.putExtras(extras); + return intent; + } + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ObjectWrapper.java b/src/com/android/launcher3/util/ObjectWrapper.java similarity index 96% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/ObjectWrapper.java rename to src/com/android/launcher3/util/ObjectWrapper.java index abfe3adbff..b69243117a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ObjectWrapper.java +++ b/src/com/android/launcher3/util/ObjectWrapper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep.util; +package com.android.launcher3.util; import android.os.Binder; import android.os.IBinder; From 769c795edfe77fe2a3f6472a5b60fd1a73618a13 Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Tue, 1 Oct 2019 13:52:22 -0700 Subject: [PATCH 066/109] Some cleanup for SwipeDetector. It is now organized as follows: - private constants - public constants - private final fields - private variable fields - constructors - public methods - private methods - public interface/abstract class This is intended to be a functional no-op. Bug: 141939911 Change-Id: Iad5a9b3b73b35641f8a4f1d52ada6adef3825c47 Tested: Built and sanity checked manually. --- .../notification/NotificationItemView.java | 4 +- .../launcher3/touch/SwipeDetector.java | 277 +++++++++--------- .../launcher3/touch/SwipeDetectorTest.java | 8 +- 3 files changed, 137 insertions(+), 152 deletions(-) diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java index 32410a64b8..717a7e93da 100644 --- a/src/com/android/launcher3/notification/NotificationItemView.java +++ b/src/com/android/launcher3/notification/NotificationItemView.java @@ -16,6 +16,8 @@ package com.android.launcher3.notification; +import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL; + import android.app.Notification; import android.content.Context; import android.graphics.Color; @@ -33,8 +35,6 @@ import com.android.launcher3.util.Themes; import java.util.List; -import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL; - /** * Utility class to manage notification UI */ diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java index 3777a41ad8..d0edfd87de 100644 --- a/src/com/android/launcher3/touch/SwipeDetector.java +++ b/src/com/android/launcher3/touch/SwipeDetector.java @@ -24,12 +24,11 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; -import com.android.launcher3.Utilities; -import com.android.launcher3.testing.TestProtocol; - import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import com.android.launcher3.Utilities; + /** * One dimensional scroll/drag/swipe gesture detector. * @@ -41,47 +40,14 @@ public class SwipeDetector { private static final boolean DBG = false; private static final String TAG = "SwipeDetector"; + private static final float ANIMATION_DURATION = 1200; + /** The minimum release velocity in pixels per millisecond that triggers fling.*/ + private static final float RELEASE_VELOCITY_PX_MS = 1.0f; - private int mScrollConditions; public static final int DIRECTION_POSITIVE = 1 << 0; public static final int DIRECTION_NEGATIVE = 1 << 1; public static final int DIRECTION_BOTH = DIRECTION_NEGATIVE | DIRECTION_POSITIVE; - private static final float ANIMATION_DURATION = 1200; - - protected int mActivePointerId = INVALID_POINTER_ID; - - /** - * The minimum release velocity in pixels per millisecond that triggers fling.. - */ - public static final float RELEASE_VELOCITY_PX_MS = 1.0f; - - /* Scroll state, this is set to true during dragging and animation. */ - private ScrollState mState = ScrollState.IDLE; - - enum ScrollState { - IDLE, - DRAGGING, // onDragStart, onDrag - SETTLING // onDragEnd - } - - public static abstract class Direction { - - abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, - boolean isRtl); - - /** - * Distance in pixels a touch can wander before we think the user is scrolling. - */ - abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos); - - abstract float getVelocity(VelocityTracker tracker, boolean isRtl); - - abstract boolean isPositive(float displacement); - - abstract boolean isNegative(float displacement); - } - public static final Direction VERTICAL = new Direction() { @Override @@ -150,35 +116,54 @@ public class SwipeDetector { } }; - //------------------- ScrollState transition diagram ----------------------------------- - // - // IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING - // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING - // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING - // SETTLING -> (View settled) -> IDLE + private final PointF mDownPos = new PointF(); + private final PointF mLastPos = new PointF(); + private final Direction mDir; + private final boolean mIsRtl; + private final float mTouchSlop; + private final float mMaxVelocity; + /* Client of this gesture detector can register a callback. */ + private final Listener mListener; - private void setState(ScrollState newState) { - if (DBG) { - Log.d(TAG, "setState:" + mState + "->" + newState); - } - // onDragStart and onDragEnd is reported ONLY on state transition - if (newState == ScrollState.DRAGGING) { - initializeDragging(); - if (mState == ScrollState.IDLE) { - reportDragStart(false /* recatch */); - } else if (mState == ScrollState.SETTLING) { - reportDragStart(true /* recatch */); - } - } - if (newState == ScrollState.SETTLING) { - reportDragEnd(); - } + private int mActivePointerId = INVALID_POINTER_ID; + private VelocityTracker mVelocityTracker; + private float mLastDisplacement; + private float mDisplacement; + private float mSubtractDisplacement; + private boolean mIgnoreSlopWhenSettling; + private int mScrollDirections; + private ScrollState mState = ScrollState.IDLE; - mState = newState; + private enum ScrollState { + IDLE, + DRAGGING, // onDragStart, onDrag + SETTLING // onDragEnd } - public boolean isDraggingOrSettling() { - return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING; + public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) { + this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources())); + } + + @VisibleForTesting + protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l, + @NonNull Direction dir, boolean isRtl) { + mListener = l; + mDir = dir; + mIsRtl = isRtl; + mTouchSlop = config.getScaledTouchSlop(); + mMaxVelocity = config.getScaledMaximumFlingVelocity(); + } + + public static long calculateDuration(float velocity, float progressNeeded) { + // TODO: make these values constants after tuning. + float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity)); + float travelDistance = Math.max(0.2f, progressNeeded); + long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance); + if (DBG) { + Log.d(TAG, String.format( + "calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded)); + } + return duration; } public int getDownX() { @@ -203,73 +188,31 @@ public class SwipeDetector { return mState == ScrollState.DRAGGING; } - private final PointF mDownPos = new PointF(); - private final PointF mLastPos = new PointF(); - private final Direction mDir; - private final boolean mIsRtl; - - private final float mTouchSlop; - private final float mMaxVelocity; - - /* Client of this gesture detector can register a callback. */ - private final Listener mListener; - - private VelocityTracker mVelocityTracker; - - private float mLastDisplacement; - private float mDisplacement; - - private float mSubtractDisplacement; - private boolean mIgnoreSlopWhenSettling; - - public interface Listener { - void onDragStart(boolean start); - - boolean onDrag(float displacement); - - default boolean onDrag(float displacement, MotionEvent event) { - return onDrag(displacement); - } - - void onDragEnd(float velocity, boolean fling); - } - - public SwipeDetector(@NonNull Context context, @NonNull Listener l, @NonNull Direction dir) { - this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources())); - } - - @VisibleForTesting - protected SwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l, - @NonNull Direction dir, boolean isRtl) { - mListener = l; - mDir = dir; - mIsRtl = isRtl; - mTouchSlop = config.getScaledTouchSlop(); - mMaxVelocity = config.getScaledMaximumFlingVelocity(); + public boolean isDraggingOrSettling() { + return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING; } public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) { - mScrollConditions = scrollDirectionFlags; + mScrollDirections = scrollDirectionFlags; mIgnoreSlopWhenSettling = ignoreSlop; } public int getScrollDirections() { - return mScrollConditions; + return mScrollDirections; } - private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) { - // reject cases where the angle or slop condition is not met. - if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop) - > Math.abs(mDisplacement)) { - return false; - } + public void finishedScrolling() { + setState(ScrollState.IDLE); + } - // Check if the client is interested in scroll in current direction. - if (((mScrollConditions & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) || - ((mScrollConditions & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement))) { - return true; - } - return false; + /** + * Returns if the start drag was towards the positive direction or negative. + * + * @see #setDetectableScrollConditions(int, boolean) + * @see #DIRECTION_BOTH + */ + public boolean wasInitialTouchPositive() { + return mDir.isPositive(mSubtractDisplacement); } public boolean onTouchEvent(MotionEvent ev) { @@ -338,16 +281,50 @@ public class SwipeDetector { return true; } - public void finishedScrolling() { - setState(ScrollState.IDLE); + //------------------- ScrollState transition diagram ----------------------------------- + // + // IDLE -> (mDisplacement > mTouchSlop) -> DRAGGING + // DRAGGING -> (MotionEvent#ACTION_UP, MotionEvent#ACTION_CANCEL) -> SETTLING + // SETTLING -> (MotionEvent#ACTION_DOWN) -> DRAGGING + // SETTLING -> (View settled) -> IDLE + + private void setState(ScrollState newState) { + if (DBG) { + Log.d(TAG, "setState:" + mState + "->" + newState); + } + // onDragStart and onDragEnd is reported ONLY on state transition + if (newState == ScrollState.DRAGGING) { + initializeDragging(); + if (mState == ScrollState.IDLE) { + reportDragStart(false /* recatch */); + } else if (mState == ScrollState.SETTLING) { + reportDragStart(true /* recatch */); + } + } + if (newState == ScrollState.SETTLING) { + reportDragEnd(); + } + + mState = newState; } - private boolean reportDragStart(boolean recatch) { + private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) { + // reject cases where the angle or slop condition is not met. + if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop) + > Math.abs(mDisplacement)) { + return false; + } + + // Check if the client is interested in scroll in current direction. + return ((mScrollDirections & DIRECTION_NEGATIVE) > 0 && mDir.isNegative(mDisplacement)) + || ((mScrollDirections & DIRECTION_POSITIVE) > 0 && mDir.isPositive(mDisplacement)); + } + + private void reportDragStart(boolean recatch) { mListener.onDragStart(!recatch); if (DBG) { Log.d(TAG, "onDragStart recatch:" + recatch); } - return true; } private void initializeDragging() { @@ -361,26 +338,15 @@ public class SwipeDetector { } } - /** - * Returns if the start drag was towards the positive direction or negative. - * - * @see #setDetectableScrollConditions(int, boolean) - * @see #DIRECTION_BOTH - */ - public boolean wasInitialTouchPositive() { - return mDir.isPositive(mSubtractDisplacement); - } - - private boolean reportDragging(MotionEvent event) { + private void reportDragging(MotionEvent event) { if (mDisplacement != mLastDisplacement) { if (DBG) { Log.d(TAG, String.format("onDrag disp=%.1f", mDisplacement)); } mLastDisplacement = mDisplacement; - return mListener.onDrag(mDisplacement - mSubtractDisplacement, event); + mListener.onDrag(mDisplacement - mSubtractDisplacement, event); } - return true; } private void reportDragEnd() { @@ -394,14 +360,33 @@ public class SwipeDetector { mListener.onDragEnd(velocity, Math.abs(velocity) > RELEASE_VELOCITY_PX_MS); } - public static long calculateDuration(float velocity, float progressNeeded) { - // TODO: make these values constants after tuning. - float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity)); - float travelDistance = Math.max(0.2f, progressNeeded); - long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance); - if (DBG) { - Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded)); + /** Listener to receive updates on the swipe. */ + public interface Listener { + void onDragStart(boolean start); + + boolean onDrag(float displacement); + + default boolean onDrag(float displacement, MotionEvent event) { + return onDrag(displacement); } - return duration; + + void onDragEnd(float velocity, boolean fling); + } + + public abstract static class Direction { + + abstract float getDisplacement(MotionEvent ev, int pointerIndex, PointF refPoint, + boolean isRtl); + + /** + * Distance in pixels a touch can wander before we think the user is scrolling. + */ + abstract float getActiveTouchSlop(MotionEvent ev, int pointerIndex, PointF downPos); + + abstract float getVelocity(VelocityTracker tracker, boolean isRtl); + + abstract boolean isPositive(float displacement); + + abstract boolean isNegative(float displacement); } } diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java index e042357083..f209fae976 100644 --- a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java +++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java @@ -25,6 +25,10 @@ import static org.mockito.Mockito.verify; import android.util.Log; import android.view.ViewConfiguration; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + import com.android.launcher3.testcomponent.TouchEventGenerator; import org.junit.Before; @@ -33,10 +37,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - @SmallTest @RunWith(AndroidJUnit4.class) public class SwipeDetectorTest { From 8ecf1b3dd3f944cc2488151111deed7f37fb81f6 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 1 Oct 2019 18:28:46 -0700 Subject: [PATCH 067/109] Waiting until context menu goes away after attempting to close it. Bug: 141770616 Change-Id: I528072e830627d825906ce7c1e3dbb914e2c814e --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 52971d92fe..ca15a3cf87 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -550,8 +550,10 @@ public final class LauncherInstrumentation { displaySize.x / 2, displaySize.y - 1, displaySize.x / 2, 0, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME); - assertTrue("Context menu is still visible after swiping up to home", - !hasLauncherObject("deep_shortcuts_container")); + try (LauncherInstrumentation.Closable c = addContextLayer( + "Swiped up from context menu to home")) { + waitUntilGone("deep_shortcuts_container"); + } } if (hasLauncherObject(WORKSPACE_RES_ID)) { log(action = "already at home"); From 7458d4aa4ac03536cf02cb06a678540c7b80cb94 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 1 Oct 2019 18:40:24 -0700 Subject: [PATCH 068/109] Logging the initial state for swiping up to home Change-Id: Iff2003f7e6dfe4072613b775722166dc5fec9e02 --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 52971d92fe..8a60db6f11 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -556,7 +556,7 @@ public final class LauncherInstrumentation { if (hasLauncherObject(WORKSPACE_RES_ID)) { log(action = "already at home"); } else { - log(action = "swiping up to home"); + log(action = "swiping up to home from " + getVisibleStateMessage()); final int finalState = mDevice.hasObject(By.pkg(getLauncherPackageName())) ? NORMAL_STATE_ORDINAL : BACKGROUND_APP_STATE_ORDINAL; From c449a6417d1928d41707f32dc9d8a056a005a383 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 2 Oct 2019 09:24:01 -0700 Subject: [PATCH 069/109] Update all apps fade interpolators for home <-> all app Previously, predictions faded in quickly but then all apps faded in linerally over entire rest of the transition. Now, all apps fades in quickly after reaching the overview threshold where predictions are opaque. Also implemented the reverse, so that predictions/all apps content remain opaque when returning home until reaching the overview threshold near the bottom, where they fade out as quickly as they faded in. We do this for 3-button mode as well. Bug: 141986013 Change-Id: Ia35ab3ac9714e89f754293445a7839e15da5313d --- .../FlingAndHoldTouchController.java | 28 +++++++++++++++---- .../PortraitStatesTouchController.java | 18 ++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java index 4a3ad1d721..e215cfe8d3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java @@ -32,8 +32,8 @@ import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.anim.Interpolators.ACCEL; +import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; -import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; @@ -132,16 +132,33 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { // Fade in prediction icons quickly, then rest of all apps after reaching overview. float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher) - OVERVIEW.getVerticalProgress(mLauncher); - builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(ACCEL, - 0, ALL_APPS_CONTENT_FADE_THRESHOLD)); - builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(LINEAR, - progressToReachOverview, 1)); + builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress( + ACCEL, + 0, + ALL_APPS_CONTENT_FADE_THRESHOLD)); + builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress( + ACCEL, + progressToReachOverview, + progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD)); // Get workspace out of the way quickly, to prepare for potential pause. builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3); builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3); builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3); return builder; + } else if (fromState == ALL_APPS && toState == NORMAL) { + AnimatorSetBuilder builder = new AnimatorSetBuilder(); + // Keep all apps/predictions opaque until the very end of the transition. + float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher); + builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress( + DEACCEL, + progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD, + progressToReachOverview)); + builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress( + DEACCEL, + 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, + 1)); + return builder; } return super.getAnimatorSetBuilderForStates(fromState, toState); } @@ -164,6 +181,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { AnimatorSetBuilder builder = new AnimatorSetBuilder(); builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2); + builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3); if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) { builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2); builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2); diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index b81edfa4ca..9813295561 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -177,6 +177,20 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr return builder; } + private AnimatorSetBuilder getNormalToAllAppsAnimation() { + AnimatorSetBuilder builder = new AnimatorSetBuilder(); + builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL, + 0, ALL_APPS_CONTENT_FADE_THRESHOLD)); + return builder; + } + + private AnimatorSetBuilder getAllAppsToNormalAnimation() { + AnimatorSetBuilder builder = new AnimatorSetBuilder(); + builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL, + 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1)); + return builder; + } + @Override protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState, LauncherState toState) { @@ -187,6 +201,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr builder = getOverviewToAllAppsAnimation(); } else if (fromState == ALL_APPS && toState == OVERVIEW) { builder = getAllAppsToOverviewAnimation(); + } else if (fromState == NORMAL && toState == ALL_APPS) { + builder = getNormalToAllAppsAnimation(); + } else if (fromState == ALL_APPS && toState == NORMAL) { + builder = getAllAppsToNormalAnimation(); } return builder; } From 0063204dbf7acd23e26ce900034e2908ee5acb8a Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Fri, 6 Sep 2019 11:32:56 -0700 Subject: [PATCH 070/109] Add nullcheck for VelocityTracker Bug:134712476 Change-Id:I7834507a4e9aadf4d89c0ed6f3eba812df7425cd (cherry picked from commit 6ef5b8abf47fb6782bb1274bca26cf9739d4389f) --- src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java b/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java index 589ad25e4f..06b5c409de 100644 --- a/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java +++ b/src/com/android/launcher3/dragndrop/FlingToDeleteHelper.java @@ -106,6 +106,7 @@ public class FlingToDeleteHelper { * @return the vector at which the item was flung, or null if no fling was detected. */ private PointF isFlingingToDelete() { + if (mVelocityTracker == null) return null; if (mDropTarget == null) { mDropTarget = (ButtonDropTarget) mLauncher.findViewById(R.id.delete_target_text); } From 01615a69d2bf8cc19ec1133d55e9844a7218e1c1 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 20 Sep 2019 12:00:07 -0700 Subject: [PATCH 071/109] Removing host deletion on startup and corresponding callbacks > Launcher deletes the phantom widget ids in loader Bug:141376165 Change-Id: Icf0542535f194f9abc67e7190f34cb60f69e9f66 --- .../model/DbDowngradeHelperTest.java | 4 +- .../launcher3/util/TestLauncherProvider.java | 2 +- src/com/android/launcher3/Launcher.java | 9 +--- .../android/launcher3/LauncherAppState.java | 20 ++----- .../android/launcher3/LauncherProvider.java | 54 ++----------------- .../LauncherProviderChangeListener.java | 11 ---- .../launcher3/provider/RestoreDbTaskTest.java | 7 +-- 7 files changed, 17 insertions(+), 90 deletions(-) delete mode 100644 src/com/android/launcher3/LauncherProviderChangeListener.java diff --git a/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java index a46617ec28..b7340cf7d0 100644 --- a/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java @@ -130,7 +130,7 @@ public class DbDowngradeHelperTest { } helper.close(); - helper = new DatabaseHelper(mContext, null, DB_FILE) { + helper = new DatabaseHelper(mContext, DB_FILE) { @Override public void onOpen(SQLiteDatabase db) { } }; @@ -161,7 +161,7 @@ public class DbDowngradeHelperTest { DbDowngradeHelper.updateSchemaFile(mSchemaFile, LauncherProvider.SCHEMA_VERSION, mContext); - DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, DB_FILE) { + DatabaseHelper dbHelper = new DatabaseHelper(mContext, DB_FILE) { @Override public void onOpen(SQLiteDatabase db) { } }; diff --git a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java index 9f833b15d8..a9c1a7c9d8 100644 --- a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java +++ b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java @@ -29,7 +29,7 @@ public class TestLauncherProvider extends LauncherProvider { private static class MyDatabaseHelper extends DatabaseHelper { public MyDatabaseHelper(Context context) { - super(context, null, null); + super(context, null); initIds(); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 9326e95dea..1a3f9dc963 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -173,7 +173,7 @@ import java.util.function.Supplier; * Default launcher application. */ public class Launcher extends BaseDraggingActivity implements LauncherExterns, - Callbacks, LauncherProviderChangeListener, UserEventDelegate, + Callbacks, UserEventDelegate, InvariantDeviceProfile.OnIDPChangeListener, PluginListener { public static final String TAG = "Launcher"; @@ -614,13 +614,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, return mLauncherView.findViewById(id); } - @Override - public void onAppWidgetHostReset() { - if (mAppWidgetHost != null) { - mAppWidgetHost.startListening(); - } - } - private LauncherCallbacks mLauncherCallbacks; /** diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index efb3d36bf1..018b48fd33 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -21,7 +21,6 @@ import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver; import android.content.ComponentName; -import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -71,10 +70,6 @@ public class LauncherAppState { } private LauncherAppState(Context context) { - if (getLocalProvider(context) == null) { - throw new RuntimeException( - "Initializing LauncherAppState in the absence of LauncherProvider"); - } Log.v(Launcher.TAG, "LauncherAppState initiated"); Preconditions.assertUIThread(); mContext = context; @@ -99,7 +94,10 @@ public class LauncherAppState { if (FeatureFlags.IS_DOGFOOD_BUILD) { filter.addAction(ACTION_FORCE_ROLOAD); } + // TODO: remove listener on terminate FeatureFlags.APP_SEARCH_IMPROVEMENTS.addChangeListener(context, mModel::forceReload); + CustomWidgetManager.INSTANCE.get(mContext) + .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts); mContext.registerReceiver(mModel, filter); UserManagerCompat.getInstance(mContext).enableAndResetCache(); @@ -149,16 +147,15 @@ public class LauncherAppState { final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); launcherApps.removeOnAppsChangedCallback(mModel); mInstallSessionTracker.unregister(); + CustomWidgetManager.INSTANCE.get(mContext).setWidgetRefreshCallback(null); + if (mNotificationDotsObserver != null) { mNotificationDotsObserver.unregister(); } } LauncherModel setLauncher(Launcher launcher) { - getLocalProvider(mContext).setLauncherProviderChangeListener(launcher); mModel.initialize(launcher); - CustomWidgetManager.INSTANCE.get(launcher) - .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts); return mModel; } @@ -184,11 +181,4 @@ public class LauncherAppState { public static InvariantDeviceProfile getIDP(Context context) { return InvariantDeviceProfile.INSTANCE.get(context); } - - private static LauncherProvider getLocalProvider(Context context) { - try (ContentProviderClient cl = context.getContentResolver() - .acquireContentProviderClient(LauncherProvider.AUTHORITY)) { - return (LauncherProvider) cl.getLocalContentProvider(); - } - } } diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index d78c1b3cc8..42927ea1cf 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -45,8 +45,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.os.Process; import android.os.UserHandle; import android.provider.BaseColumns; @@ -69,7 +67,6 @@ import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.NoLocaleSQLiteHelper; import com.android.launcher3.util.PackageManagerHelper; -import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.Thunk; import org.xmlpull.v1.XmlPullParser; @@ -100,9 +97,6 @@ public class LauncherProvider extends ContentProvider { static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; - private final ChangeListenerWrapper mListenerWrapper = new ChangeListenerWrapper(); - private Handler mListenerHandler; - protected DatabaseHelper mOpenHelper; /** @@ -122,7 +116,6 @@ public class LauncherProvider extends ContentProvider { if (FeatureFlags.IS_DOGFOOD_BUILD) { Log.d(TAG, "Launcher process started"); } - mListenerHandler = new Handler(mListenerWrapper); // The content provider exists for the entire duration of the launcher main process and // is the first component to get created. @@ -130,14 +123,6 @@ public class LauncherProvider extends ContentProvider { return true; } - /** - * Sets a provider listener. - */ - public void setLauncherProviderChangeListener(LauncherProviderChangeListener listener) { - Preconditions.assertUIThread(); - mListenerWrapper.mListener = listener; - } - @Override public String getType(Uri uri) { SqlArguments args = new SqlArguments(uri, null, null); @@ -153,7 +138,7 @@ public class LauncherProvider extends ContentProvider { */ protected synchronized void createDbIfNotExists() { if (mOpenHelper == null) { - mOpenHelper = new DatabaseHelper(getContext(), mListenerHandler); + mOpenHelper = new DatabaseHelper(getContext()); if (RestoreDbTask.isPending(getContext())) { if (!RestoreDbTask.performRestore(getContext(), mOpenHelper, @@ -552,15 +537,13 @@ public class LauncherProvider extends ContentProvider { * The class is subclassed in tests to create an in-memory db. */ public static class DatabaseHelper extends NoLocaleSQLiteHelper implements LayoutParserCallback { - private final BackupManager mBackupManager; - private final Handler mWidgetHostResetHandler; private final Context mContext; private int mMaxItemId = -1; private int mMaxScreenId = -1; private boolean mBackupTableExists; - DatabaseHelper(Context context, Handler widgetHostResetHandler) { - this(context, widgetHostResetHandler, LauncherFiles.LAUNCHER_DB); + DatabaseHelper(Context context) { + this(context, LauncherFiles.LAUNCHER_DB); // Table creation sometimes fails silently, which leads to a crash loop. // This way, we will try to create a table every time after crash, so the device // would eventually be able to recover. @@ -577,12 +560,9 @@ public class LauncherProvider extends ContentProvider { /** * Constructor used in tests and for restore. */ - public DatabaseHelper( - Context context, Handler widgetHostResetHandler, String tableName) { + public DatabaseHelper(Context context, String tableName) { super(context, tableName, SCHEMA_VERSION); mContext = context; - mWidgetHostResetHandler = widgetHostResetHandler; - mBackupManager = new BackupManager(mContext); } protected void initIds() { @@ -621,13 +601,6 @@ public class LauncherProvider extends ContentProvider { * Overriden in tests. */ protected void onEmptyDbCreated() { - // Database was just created, so wipe any previous widgets - if (mWidgetHostResetHandler != null) { - newLauncherWidgetHost().deleteHost(); - mWidgetHostResetHandler.sendEmptyMessage( - ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET); - } - // Set the flag for empty DB Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit(); } @@ -1027,23 +1000,4 @@ public class LauncherProvider extends ContentProvider { } } } - - private static class ChangeListenerWrapper implements Handler.Callback { - - private static final int MSG_APP_WIDGET_HOST_RESET = 2; - - private LauncherProviderChangeListener mListener; - - @Override - public boolean handleMessage(Message msg) { - if (mListener != null) { - switch (msg.what) { - case MSG_APP_WIDGET_HOST_RESET: - mListener.onAppWidgetHostReset(); - break; - } - } - return true; - } - } } diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java deleted file mode 100644 index 6afe88526d..0000000000 --- a/src/com/android/launcher3/LauncherProviderChangeListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.android.launcher3; - -/** - * This class is a listener for {@link LauncherProvider} changes. It gets notified in the - * sendNotify method. This listener is needed because by default the Launcher suppresses - * standard data change callbacks. - */ -public interface LauncherProviderChangeListener { - - void onAppWidgetHostReset(); -} diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java index 6fa8d62a17..27990f4305 100644 --- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java @@ -1,8 +1,11 @@ package com.android.launcher3.provider; +import static org.junit.Assert.assertEquals; + import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; + import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; @@ -13,8 +16,6 @@ import com.android.launcher3.LauncherSettings.Favorites; import org.junit.Test; import org.junit.runner.RunWith; -import static org.junit.Assert.assertEquals; - /** * Tests for {@link RestoreDbTask} */ @@ -82,7 +83,7 @@ public class RestoreDbTaskTest { private final long mProfileId; MyDatabaseHelper(long profileId) { - super(InstrumentationRegistry.getContext(), null, null); + super(InstrumentationRegistry.getContext(), null); mProfileId = profileId; } From b0adac23e009618189ec804a9689f5b24097dabb Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 2 Oct 2019 14:27:25 -0700 Subject: [PATCH 072/109] Removing access to LauncherModel.getCallbacks Bug: 137568159 Change-Id: Ic074dec6a8981a4b9aabf028cf3b878b532abb11 --- .../android/launcher3/InstallShortcutReceiver.java | 7 +++---- .../launcher3/testing/TestInformationHandler.java | 5 ++--- .../launcher3/ui/AbstractLauncherUiTest.java | 14 +++----------- .../launcher3/tapl/LauncherInstrumentation.java | 2 +- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index aa975bd4dc..c9eca9dadd 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -69,7 +69,6 @@ public class InstallShortcutReceiver extends BroadcastReceiver { public static final int FLAG_ACTIVITY_PAUSED = 1; public static final int FLAG_LOADER_RUNNING = 2; public static final int FLAG_DRAG_AND_DROP = 4; - public static final int FLAG_BULK_ADD = 4; // Determines whether to defer installing shortcuts immediately until // processAllPendingInstalls() is called. @@ -110,8 +109,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { @WorkerThread private static void flushQueueInBackground(Context context) { - LauncherModel model = LauncherAppState.getInstance(context).getModel(); - if (model.getCallback() == null) { + if (Launcher.ACTIVITY_TRACKER.getCreatedActivity() == null) { // Launcher not loaded return; } @@ -146,7 +144,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { } prefs.edit().remove(APPS_PENDING_INSTALL).apply(); if (!installQueue.isEmpty()) { - model.addAndBindAddedWorkspaceItems(installQueue); + LauncherAppState.getInstance(context).getModel() + .addAndBindAddedWorkspaceItems(installQueue); } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 619293bd84..05596bd9cd 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -29,7 +29,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsStore; @@ -170,7 +169,7 @@ public class TestInformationHandler implements ResourceBasedOverride { } protected boolean isLauncherInitialized() { - final LauncherModel model = LauncherAppState.getInstance(mContext).getModel(); - return model.getCallback() == null || model.isModelLoaded(); + return Launcher.ACTIVITY_TRACKER.getCreatedActivity() == null + || LauncherAppState.getInstance(mContext).getModel().isModelLoaded(); } } diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 63657dd9cb..5bedd62182 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -48,7 +48,6 @@ import androidx.test.uiautomator.Until; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; @@ -183,7 +182,7 @@ public abstract class AbstractLauncherUiTest { public void verifyLauncherState() { try { // Limits UI tests affecting tests running after them. - waitForModelLoaded(); + mLauncher.waitForLauncherInitialized(); } catch (Throwable t) { Log.e(TAG, "Couldn't deinit after a test, exiting tests, see logs for failures that " @@ -222,14 +221,7 @@ public abstract class AbstractLauncherUiTest { } catch (Throwable t) { throw new IllegalArgumentException(t); } - waitForModelLoaded(); - } - - protected void waitForModelLoaded() { - waitForLauncherCondition("Launcher model didn't load", launcher -> { - final LauncherModel model = LauncherAppState.getInstance(mTargetContext).getModel(); - return model.getCallback() == null || model.isModelLoaded(); - }); + mLauncher.waitForLauncherInitialized(); } /** @@ -258,7 +250,7 @@ public abstract class AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); - waitForModelLoaded(); + mLauncher.waitForLauncherInitialized(); } /** diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index a03f8ab3b9..2f7e50a971 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -495,7 +495,7 @@ public final class LauncherInstrumentation { } } - private void waitForLauncherInitialized() { + public void waitForLauncherInitialized() { for (int i = 0; i < 100; ++i) { if (getTestInfo( TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED). From e7b00128c7da366345180647a070a1547e4f9ef9 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 2 Oct 2019 16:13:34 -0700 Subject: [PATCH 073/109] Removing static instance of LauncherAppsCompat and unnecessary wrapper classes Bug: 141376165 Change-Id: I8c1f1ab7d83ec50fe9c7bf39960ef9c360025ec7 --- .../com/android/quickstep/RecentsModel.java | 35 +-- .../src/com/android/quickstep/TaskUtils.java | 9 +- .../quickstep/AppPredictionsUITests.java | 4 +- .../launcher3/BaseDraggingActivity.java | 4 +- .../launcher3/InstallShortcutReceiver.java | 10 +- src/com/android/launcher3/Launcher.java | 6 +- .../android/launcher3/LauncherAppState.java | 32 ++- src/com/android/launcher3/LauncherModel.java | 16 +- .../launcher3/SecondaryDropTarget.java | 10 +- .../launcher3/SessionCommitReceiver.java | 11 +- src/com/android/launcher3/Utilities.java | 6 +- .../launcher3/WidgetPreviewLoader.java | 2 +- .../launcher3/compat/LauncherAppsCompat.java | 88 -------- .../compat/LauncherAppsCompatVL.java | 210 ------------------ .../launcher3/dragndrop/AddItemActivity.java | 4 +- .../PinShortcutRequestActivityInfo.java | 10 +- .../android/launcher3/icons/IconCache.java | 6 +- .../model/AddWorkspaceItemsTask.java | 4 +- .../android/launcher3/model/AllAppsList.java | 19 +- .../android/launcher3/model/LoaderCursor.java | 8 +- .../android/launcher3/model/LoaderTask.java | 10 +- .../launcher3/model/PackageUpdatedTask.java | 14 +- .../model/SdCardAvailableReceiver.java | 6 +- .../android/launcher3/model/WidgetItem.java | 2 +- .../launcher3/pm/PackageInstallerCompat.java | 15 +- .../PinRequestHelper.java} | 70 +----- .../ShortcutConfigActivityInfo.java | 69 +++++- .../launcher3/util/PackageManagerHelper.java | 54 ++++- .../util/SimpleBroadcastReceiver.java | 48 ++++ .../widget/PendingAddShortcutInfo.java | 2 +- .../android/launcher3/model/WidgetsModel.java | 13 +- .../launcher3/model/LoaderCursorTest.java | 55 ++--- .../launcher3/ui/AbstractLauncherUiTest.java | 7 +- 33 files changed, 318 insertions(+), 541 deletions(-) delete mode 100644 src/com/android/launcher3/compat/LauncherAppsCompat.java delete mode 100644 src/com/android/launcher3/compat/LauncherAppsCompatVL.java rename src/com/android/launcher3/{compat/LauncherAppsCompatVO.java => pm/PinRequestHelper.java} (59%) rename src/com/android/launcher3/{compat => pm}/ShortcutConfigActivityInfo.java (66%) create mode 100644 src/com/android/launcher3/util/SimpleBroadcastReceiver.java diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 2e59ed5e48..e86a1c100e 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -25,6 +25,7 @@ import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; +import android.content.pm.LauncherApps; import android.os.Build; import android.os.Looper; import android.os.Process; @@ -32,8 +33,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; -import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; @@ -211,18 +210,28 @@ public class RecentsModel extends TaskStackChangeListener { } private void setupPackageListener() { - LauncherAppsCompat.getInstance(mContext) - .addOnAppsChangedCallback(new OnAppsChangedCallbackCompat() { - @Override - public void onPackageRemoved(String packageName, UserHandle user) { - mIconCache.invalidatePackage(packageName); - } + mContext.getSystemService(LauncherApps.class).registerCallback(new LauncherApps.Callback() { + @Override + public void onPackageRemoved(String packageName, UserHandle user) { + mIconCache.invalidatePackage(packageName); + } - @Override - public void onPackageChanged(String packageName, UserHandle user) { - mIconCache.invalidatePackage(packageName); - } - }); + @Override + public void onPackageChanged(String packageName, UserHandle user) { + mIconCache.invalidatePackage(packageName); + } + + @Override + public void onPackageAdded(String packageName, UserHandle user) { } + + @Override + public void onPackagesAvailable( + String[] packageNames, UserHandle user, boolean replacing) { } + + @Override + public void onPackagesUnavailable( + String[] packageNames, UserHandle user, boolean replacing) { } + }); } public void addThumbnailChangeListener(TaskThumbnailChangeListener listener) { diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java index 5f76ca71d6..230a22a375 100644 --- a/quickstep/src/com/android/quickstep/TaskUtils.java +++ b/quickstep/src/com/android/quickstep/TaskUtils.java @@ -23,9 +23,9 @@ import android.content.pm.PackageManager; import android.os.UserHandle; import android.util.Log; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.PackageManagerHelper; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -44,15 +44,14 @@ public final class TaskUtils { * TODO: remove this once we switch to getting the icon and label from IconCache. */ public static CharSequence getTitle(Context context, Task task) { - LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(context); - PackageManager packageManager = context.getPackageManager(); UserHandle user = UserHandle.of(task.key.userId); - ApplicationInfo applicationInfo = launcherAppsCompat.getApplicationInfo( - task.getTopComponent().getPackageName(), 0, user); + ApplicationInfo applicationInfo = new PackageManagerHelper(context) + .getApplicationInfo(task.getTopComponent().getPackageName(), user, 0); if (applicationInfo == null) { Log.e(TAG, "Failed to get title for task " + task); return ""; } + PackageManager packageManager = context.getPackageManager(); return packageManager.getUserBadgedLabel( applicationInfo.loadLabel(packageManager), user); } diff --git a/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java b/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java index 7801775d48..8e4762da7f 100644 --- a/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java +++ b/quickstep/tests/src/com/android/quickstep/AppPredictionsUITests.java @@ -24,6 +24,7 @@ import android.app.prediction.AppTarget; import android.app.prediction.AppTargetId; import android.content.ComponentName; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.os.Process; import android.view.View; @@ -35,7 +36,6 @@ import com.android.launcher3.Launcher; import com.android.launcher3.appprediction.PredictionRowView; import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.model.AppLaunchTracker; import org.junit.After; @@ -60,7 +60,7 @@ public class AppPredictionsUITests extends AbstractQuickStepTest { public void setUp() throws Exception { super.setUp(); - List activities = LauncherAppsCompat.getInstance(mTargetContext) + List activities = mTargetContext.getSystemService(LauncherApps.class) .getActivityList(null, Process.myUserHandle()); mSampleApp1 = activities.get(0); mSampleApp2 = activities.get(1); diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index e2ef337c53..00a06ae633 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -19,6 +19,7 @@ package com.android.launcher3; import android.app.ActivityOptions; import android.content.ActivityNotFoundException; import android.content.Intent; +import android.content.pm.LauncherApps; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; @@ -33,7 +34,6 @@ import android.widget.Toast; import androidx.annotation.Nullable; import com.android.launcher3.LauncherSettings.Favorites; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.uioverrides.DejankBinderTracker; @@ -168,7 +168,7 @@ public abstract class BaseDraggingActivity extends BaseActivity AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(), Process.myUserHandle(), sourceContainer); } else { - LauncherAppsCompat.getInstance(this).startActivityForProfile( + getSystemService(LauncherApps.class).startMainActivity( intent.getComponent(), user, intent.getSourceBounds(), optsBundle); AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(), user, sourceContainer); diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index aa975bd4dc..638b505bbc 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -26,6 +26,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; @@ -40,7 +41,6 @@ import android.util.Pair; import androidx.annotation.WorkerThread; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; @@ -124,7 +124,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { return; } - LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + LauncherApps launcherApps = context.getSystemService(LauncherApps.class); for (String encoded : strings) { PendingInstallShortcutInfo info = decode(encoded, context); if (info == null) { @@ -133,7 +133,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { String pkg = getIntentPackage(info.launchIntent); if (!TextUtils.isEmpty(pkg) - && !launcherApps.isPackageEnabledForProfile(pkg, info.user) + && !launcherApps.isPackageEnabled(pkg, info.user) && !info.isActivity) { if (DBG) { Log.d(TAG, "Ignoring shortcut for absent package: " + info.launchIntent); @@ -520,7 +520,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { try { Decoder decoder = new Decoder(encoded, context); if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) { - LauncherActivityInfo info = LauncherAppsCompat.getInstance(context) + LauncherActivityInfo info = context.getSystemService(LauncherApps.class) .resolveActivity(decoder.launcherIntent, decoder.user); if (info != null) { return new PendingInstallShortcutInfo(info, context); @@ -610,7 +610,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { return original; } - LauncherActivityInfo info = LauncherAppsCompat.getInstance(original.mContext) + LauncherActivityInfo info = original.mContext.getSystemService(LauncherApps.class) .resolveActivity(original.launchIntent, original.user); if (info == null) { return original; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 9326e95dea..5c72436fbf 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -90,7 +90,6 @@ import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.compat.LauncherAppsCompatVO; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.dragndrop.DragController; @@ -110,6 +109,7 @@ import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.ModelWriter; import com.android.launcher3.notification.NotificationListener; +import com.android.launcher3.pm.PinRequestHelper; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; import com.android.launcher3.qsb.QsbContainerView; @@ -1237,8 +1237,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, WorkspaceItemInfo info = null; if (Utilities.ATLEAST_OREO) { - info = LauncherAppsCompatVO.createWorkspaceItemFromPinItemRequest( - this, LauncherAppsCompatVO.getPinItemRequest(data), 0); + info = PinRequestHelper.createWorkspaceItemFromPinItemRequest( + this, PinRequestHelper.getPinItemRequest(data), 0); } if (info == null) { diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index efb3d36bf1..f687c9df9c 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -24,11 +24,10 @@ import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; +import android.content.pm.LauncherApps; import android.os.Handler; import android.util.Log; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; @@ -39,6 +38,7 @@ import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SecureSettingsObserver; +import com.android.launcher3.util.SimpleBroadcastReceiver; import com.android.launcher3.widget.custom.CustomWidgetManager; public class LauncherAppState { @@ -57,6 +57,7 @@ public class LauncherAppState { private final SecureSettingsObserver mNotificationDotsObserver; private final InstallSessionTracker mInstallSessionTracker; + private final SimpleBroadcastReceiver mModelChangeReceiver; public static LauncherAppState getInstance(final Context context) { return INSTANCE.get(context); @@ -84,24 +85,20 @@ public class LauncherAppState { mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); - LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel); - - // Register intent receivers - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_LOCALE_CHANGED); - // For handling managed profiles - filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); - filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); + mModelChangeReceiver = new SimpleBroadcastReceiver(mModel::onBroadcastIntent); + mContext.getSystemService(LauncherApps.class).registerCallback(mModel); + mModelChangeReceiver.register(mContext, Intent.ACTION_LOCALE_CHANGED, + Intent.ACTION_MANAGED_PROFILE_ADDED, + Intent.ACTION_MANAGED_PROFILE_REMOVED, + Intent.ACTION_MANAGED_PROFILE_AVAILABLE, + Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE, + Intent.ACTION_MANAGED_PROFILE_UNLOCKED); if (FeatureFlags.IS_DOGFOOD_BUILD) { - filter.addAction(ACTION_FORCE_ROLOAD); + mModelChangeReceiver.register(mContext, ACTION_FORCE_ROLOAD); } FeatureFlags.APP_SEARCH_IMPROVEMENTS.addChangeListener(context, mModel::forceReload); - mContext.registerReceiver(mModel, filter); UserManagerCompat.getInstance(mContext).enableAndResetCache(); mInvariantDeviceProfile.addOnChangeListener(this::onIdpChanged); new Handler().post( () -> mInvariantDeviceProfile.verifyConfigChangedInBackground(context)); @@ -145,9 +142,8 @@ public class LauncherAppState { * Call from Application.onTerminate(), which is not guaranteed to ever be called. */ public void onTerminate() { - mContext.unregisterReceiver(mModel); - final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); - launcherApps.removeOnAppsChangedCallback(mModel); + mContext.unregisterReceiver(mModelChangeReceiver); + mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel); mInstallSessionTracker.unregister(); if (mNotificationDotsObserver != null) { mNotificationDotsObserver.unregister(); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index f360325194..bea25e07ee 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -21,9 +21,8 @@ import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; -import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; +import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.ShortcutInfo; import android.os.UserHandle; @@ -33,7 +32,6 @@ import android.util.Pair; import androidx.annotation.Nullable; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; @@ -76,8 +74,7 @@ import java.util.function.Supplier; * LauncherModel object held in a static. Also provide APIs for updating the database state * for the Launcher. */ -public class LauncherModel extends BroadcastReceiver - implements LauncherAppsCompat.OnAppsChangedCallbackCompat, InstallSessionTracker.Callback { +public class LauncherModel extends LauncherApps.Callback implements InstallSessionTracker.Callback { private static final boolean DEBUG_RECEIVER = false; static final String TAG = "Launcher.Model"; @@ -217,12 +214,7 @@ public class LauncherModel extends BroadcastReceiver enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, shortcuts, user, false)); } - /** - * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and - * ACTION_PACKAGE_CHANGED. - */ - @Override - public void onReceive(Context context, Intent intent) { + public void onBroadcastIntent(Intent intent) { if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent); final String action = intent.getAction(); if (Intent.ACTION_LOCALE_CHANGED.equals(action)) { @@ -230,7 +222,7 @@ public class LauncherModel extends BroadcastReceiver forceReload(); } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action) || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { - UserManagerCompat.getInstance(context).enableAndResetCache(); + UserManagerCompat.getInstance(mApp.getContext()).enableAndResetCache(); forceReload(); } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action) || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action) || diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java index c8c590d9de..3c2ed72592 100644 --- a/src/com/android/launcher3/SecondaryDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -16,6 +16,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; @@ -28,12 +29,12 @@ import android.view.View; import android.widget.Toast; import com.android.launcher3.Launcher.OnResumeCallback; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.logging.FileLog; import com.android.launcher3.logging.LoggerUtils; import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Themes; import java.net.URISyntaxException; @@ -157,7 +158,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList user = item.user; } if (intent != null) { - LauncherActivityInfo info = LauncherAppsCompat.getInstance(mLauncher) + LauncherActivityInfo info = mLauncher.getSystemService(LauncherApps.class) .resolveActivity(intent, user); if (info != null && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) { @@ -287,9 +288,8 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList @Override public void onLauncherResume() { // We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well. - if (LauncherAppsCompat.getInstance(mContext) - .getApplicationInfo(mPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, - mDragObject.dragInfo.user) == null) { + if (new PackageManagerHelper(mContext).getApplicationInfo(mPackageName, + mDragObject.dragInfo.user, PackageManager.MATCH_UNINSTALLED_PACKAGES) == null) { mDragObject.dragSource = mOriginal; mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true); } else { diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index 55402dd59b..8dedc6c498 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; @@ -39,7 +40,6 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Log; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.util.Executors; @@ -85,9 +85,8 @@ public class SessionCommitReceiver extends BroadcastReceiver { public static void queuePromiseAppIconAddition(Context context, SessionInfo sessionInfo) { String packageName = sessionInfo.getAppPackageName(); - List activities = LauncherAppsCompat.getInstance(context) - .getActivityList(packageName, getUserHandle(sessionInfo)); - if (activities == null || activities.isEmpty()) { + if (context.getSystemService(LauncherApps.class) + .getActivityList(packageName, getUserHandle(sessionInfo)).isEmpty()) { // Ensure application isn't already installed. queueAppIconAddition(context, packageName, sessionInfo.getAppLabel(), sessionInfo.getAppIcon(), getUserHandle(sessionInfo)); @@ -95,9 +94,9 @@ public class SessionCommitReceiver extends BroadcastReceiver { } public static void queueAppIconAddition(Context context, String packageName, UserHandle user) { - List activities = LauncherAppsCompat.getInstance(context) + List activities = context.getSystemService(LauncherApps.class) .getActivityList(packageName, user); - if (activities == null || activities.isEmpty()) { + if (activities.isEmpty()) { // no activity found return; } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 6ddebe75d0..d87ff3e4f6 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -27,6 +27,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.res.Resources; @@ -59,12 +60,11 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Interpolator; -import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.compat.ShortcutConfigActivityInfo; import com.android.launcher3.dragndrop.FolderAdaptiveIcon; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.graphics.TintedDrawableSpan; import com.android.launcher3.icons.LauncherIcons; +import com.android.launcher3.pm.ShortcutConfigActivityInfo; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.IntArray; @@ -526,7 +526,7 @@ public final class Utilities { boolean flattenDrawable, Object[] outObj) { LauncherAppState appState = LauncherAppState.getInstance(launcher); if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - LauncherActivityInfo activityInfo = LauncherAppsCompat.getInstance(launcher) + LauncherActivityInfo activityInfo = launcher.getSystemService(LauncherApps.class) .resolveActivity(info.getIntent(), info.user); outObj[0] = activityInfo; return (activityInfo != null) ? appState.getIconCache() diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index abf6cbd5ad..76262da7b4 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -35,13 +35,13 @@ import android.util.Pair; import androidx.annotation.Nullable; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.compat.ShortcutConfigActivityInfo; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.ShadowGenerator; import com.android.launcher3.model.WidgetItem; +import com.android.launcher3.pm.ShortcutConfigActivityInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.Executors; import com.android.launcher3.util.PackageUserKey; diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java deleted file mode 100644 index 047346dcaf..0000000000 --- a/src/com/android/launcher3/compat/LauncherAppsCompat.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2014 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.compat; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.LauncherActivityInfo; -import android.content.pm.ShortcutInfo; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.UserHandle; - -import androidx.annotation.Nullable; - -import com.android.launcher3.Utilities; -import com.android.launcher3.util.PackageUserKey; - -import java.util.List; - -public abstract class LauncherAppsCompat { - - public interface OnAppsChangedCallbackCompat { - default void onPackageRemoved(String packageName, UserHandle user) { } - default void onPackageAdded(String packageName, UserHandle user) { } - default void onPackageChanged(String packageName, UserHandle user) { } - default void onPackagesAvailable(String[] packageNames, UserHandle user, - boolean replacing) { } - default void onPackagesUnavailable(String[] packageNames, UserHandle user, - boolean replacing) { } - default void onPackagesSuspended(String[] packageNames, UserHandle user) { } - default void onPackagesUnsuspended(String[] packageNames, UserHandle user) { } - default void onShortcutsChanged(String packageName, List shortcuts, - UserHandle user) { } - } - - protected LauncherAppsCompat() { - } - - private static LauncherAppsCompat sInstance; - private static final Object sInstanceLock = new Object(); - - public static LauncherAppsCompat getInstance(Context context) { - synchronized (sInstanceLock) { - if (sInstance == null) { - if (Utilities.ATLEAST_OREO) { - sInstance = new LauncherAppsCompatVO(context.getApplicationContext()); - } else { - sInstance = new LauncherAppsCompatVL(context.getApplicationContext()); - } - } - return sInstance; - } - } - - public abstract List getActivityList(String packageName, - UserHandle user); - public abstract LauncherActivityInfo resolveActivity(Intent intent, - UserHandle user); - public abstract void startActivityForProfile(ComponentName component, UserHandle user, - Rect sourceBounds, Bundle opts); - public abstract ApplicationInfo getApplicationInfo( - String packageName, int flags, UserHandle user); - public abstract void showAppDetailsForProfile(ComponentName component, UserHandle user, - Rect sourceBounds, Bundle opts); - public abstract void addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener); - public abstract void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat listener); - public abstract boolean isPackageEnabledForProfile(String packageName, UserHandle user); - public abstract boolean isActivityEnabledForProfile(ComponentName component, - UserHandle user); - public abstract List getCustomShortcutActivityList( - @Nullable PackageUserKey packageUser); -} diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java deleted file mode 100644 index f1b9756e4a..0000000000 --- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2014 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.compat; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.LauncherActivityInfo; -import android.content.pm.LauncherApps; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ShortcutInfo; -import android.graphics.Rect; -import android.os.Bundle; -import android.os.Process; -import android.os.UserHandle; -import android.util.ArrayMap; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL; -import com.android.launcher3.testing.TestProtocol; -import com.android.launcher3.util.PackageUserKey; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class LauncherAppsCompatVL extends LauncherAppsCompat { - - protected final LauncherApps mLauncherApps; - protected final Context mContext; - - private final ArrayMap mCallbacks = - new ArrayMap<>(); - - LauncherAppsCompatVL(Context context) { - mContext = context; - mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); - } - - @Override - public List getActivityList(String packageName, UserHandle user) { - return mLauncherApps.getActivityList(packageName, user); - } - - @Override - public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { - return mLauncherApps.resolveActivity(intent, user); - } - - @Override - public void startActivityForProfile(ComponentName component, UserHandle user, - Rect sourceBounds, Bundle opts) { - mLauncherApps.startMainActivity(component, user, sourceBounds, opts); - } - - @Override - public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) { - final boolean isPrimaryUser = Process.myUserHandle().equals(user); - if (!isPrimaryUser && (flags == 0)) { - // We are looking for an installed app on a secondary profile. Prior to O, the only - // entry point for work profiles is through the LauncherActivity. - List activityList = - mLauncherApps.getActivityList(packageName, user); - return activityList.size() > 0 ? activityList.get(0).getApplicationInfo() : null; - } - try { - ApplicationInfo info = - mContext.getPackageManager().getApplicationInfo(packageName, flags); - // There is no way to check if the app is installed for managed profile. But for - // primary profile, we can still have this check. - if (isPrimaryUser && ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) - || !info.enabled) { - return null; - } - return info; - } catch (PackageManager.NameNotFoundException e) { - // Package not found - return null; - } - } - - @Override - public void showAppDetailsForProfile(ComponentName component, UserHandle user, - Rect sourceBounds, Bundle opts) { - mLauncherApps.startAppDetailsActivity(component, user, sourceBounds, opts); - } - - @Override - public void addOnAppsChangedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) { - WrappedCallback wrappedCallback = new WrappedCallback(callback); - synchronized (mCallbacks) { - mCallbacks.put(callback, wrappedCallback); - } - mLauncherApps.registerCallback(wrappedCallback); - } - - @Override - public void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) { - final WrappedCallback wrappedCallback; - synchronized (mCallbacks) { - wrappedCallback = mCallbacks.remove(callback); - } - if (wrappedCallback != null) { - mLauncherApps.unregisterCallback(wrappedCallback); - } - } - - @Override - public boolean isPackageEnabledForProfile(String packageName, UserHandle user) { - return mLauncherApps.isPackageEnabled(packageName, user); - } - - @Override - public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) { - return mLauncherApps.isActivityEnabled(component, user); - } - - private static class WrappedCallback extends LauncherApps.Callback { - private final LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback; - - public WrappedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) { - mCallback = callback; - } - - @Override - public void onPackageRemoved(String packageName, UserHandle user) { - mCallback.onPackageRemoved(packageName, user); - } - - @Override - public void onPackageAdded(String packageName, UserHandle user) { - mCallback.onPackageAdded(packageName, user); - } - - @Override - public void onPackageChanged(String packageName, UserHandle user) { - mCallback.onPackageChanged(packageName, user); - } - - @Override - public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) { - mCallback.onPackagesAvailable(packageNames, user, replacing); - } - - @Override - public void onPackagesUnavailable(String[] packageNames, UserHandle user, - boolean replacing) { - mCallback.onPackagesUnavailable(packageNames, user, replacing); - } - - @Override - public void onPackagesSuspended(String[] packageNames, UserHandle user) { - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.APP_NOT_DISABLED, "onPackagesSuspended: " + - Arrays.toString(packageNames)); - } - mCallback.onPackagesSuspended(packageNames, user); - } - - @Override - public void onPackagesUnsuspended(String[] packageNames, UserHandle user) { - mCallback.onPackagesUnsuspended(packageNames, user); - } - - @Override - public void onShortcutsChanged(@NonNull String packageName, - @NonNull List shortcuts, - @NonNull UserHandle user) { - mCallback.onShortcutsChanged(packageName, shortcuts, user); - } - } - - @Override - public List getCustomShortcutActivityList( - @Nullable PackageUserKey packageUser) { - List result = new ArrayList<>(); - if (packageUser != null && !packageUser.mUser.equals(Process.myUserHandle())) { - return result; - } - PackageManager pm = mContext.getPackageManager(); - for (ResolveInfo info : - pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0)) { - if (packageUser == null || packageUser.mPackageName - .equals(info.activityInfo.packageName)) { - result.add(new ShortcutConfigActivityInfoVL(info.activityInfo)); - } - } - return result; - } -} - diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index b8981b6a3c..1b0567fe96 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -51,8 +51,8 @@ import com.android.launcher3.LauncherAppWidgetHost; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.compat.LauncherAppsCompatVO; import com.android.launcher3.model.WidgetItem; +import com.android.launcher3.pm.PinRequestHelper; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.InstantAppResolver; @@ -93,7 +93,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mRequest = LauncherAppsCompatVO.getPinItemRequest(getIntent()); + mRequest = PinRequestHelper.getPinItemRequest(getIntent()); if (mRequest == null) { finish(); return; diff --git a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java index 91a31aa090..09062a4b84 100644 --- a/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java +++ b/src/com/android/launcher3/dragndrop/PinShortcutRequestActivityInfo.java @@ -29,14 +29,14 @@ import android.os.Build; import android.os.Process; import com.android.launcher3.FastBitmapDrawable; -import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.IconCache; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; -import com.android.launcher3.compat.LauncherAppsCompatVO; -import com.android.launcher3.compat.ShortcutConfigActivityInfo; +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.icons.IconCache; +import com.android.launcher3.pm.PinRequestHelper; +import com.android.launcher3.pm.ShortcutConfigActivityInfo; /** * Extension of ShortcutConfigActivityInfo to be used in the confirmation prompt for pin item @@ -88,7 +88,7 @@ class PinShortcutRequestActivityInfo extends ShortcutConfigActivityInfo { LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY + LauncherAnimUtils.SPRING_LOADED_TRANSITION_MS; // Delay the actual accept() call until the drop animation is complete. - return LauncherAppsCompatVO.createWorkspaceItemFromPinItemRequest( + return PinRequestHelper.createWorkspaceItemFromPinItemRequest( mContext, mRequest, duration); } diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index b1818a0659..9886f53863 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; @@ -42,7 +43,6 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherFiles; 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.config.FeatureFlags; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; @@ -66,7 +66,7 @@ public class IconCache extends BaseIconCache { private final CachingLogic mComponentWithLabelCachingLogic; private final CachingLogic mLauncherActivityInfoCachingLogic; - private final LauncherAppsCompat mLauncherApps; + private final LauncherApps mLauncherApps; private final UserManagerCompat mUserManager; private final InstantAppResolver mInstantAppResolver; private final IconProvider mIconProvider; @@ -78,7 +78,7 @@ public class IconCache extends BaseIconCache { inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false); mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); - mLauncherApps = LauncherAppsCompat.getInstance(mContext); + mLauncherApps = mContext.getSystemService(LauncherApps.class); mUserManager = UserManagerCompat.getInstance(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); mIconProvider = IconProvider.INSTANCE.get(context); diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index 844a2a61a1..227bb22e2e 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -17,6 +17,7 @@ package com.android.launcher3.model; import android.content.Intent; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller.SessionInfo; import android.os.UserHandle; import android.util.LongSparseArray; @@ -31,7 +32,6 @@ import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherModel.CallbackTask; import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.pm.PackageInstallerCompat; import com.android.launcher3.util.GridOccupancy; @@ -90,7 +90,7 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { PackageInstallerCompat packageInstaller = PackageInstallerCompat.getInstance(app.getContext()); - LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(app.getContext()); + LauncherApps launcherApps = app.getContext().getSystemService(LauncherApps.class); for (ItemInfo item : filteredItems) { // Find appropriate space for the item. diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 1e1df88d39..9f1843f04e 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -23,6 +23,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.os.LocaleList; import android.os.Process; import android.os.UserHandle; @@ -35,11 +36,11 @@ import com.android.launcher3.AppFilter; import com.android.launcher3.AppInfo; import com.android.launcher3.PromiseAppInfo; import com.android.launcher3.compat.AlphabeticIndexCompat; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.icons.IconCache; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.ItemInfoMatcher; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.SafeCloseable; import java.util.ArrayList; @@ -110,8 +111,8 @@ public class AllAppsList { } public void addPromiseApp(Context context, PackageInstallInfo installInfo) { - ApplicationInfo applicationInfo = LauncherAppsCompat.getInstance(context) - .getApplicationInfo(installInfo.packageName, 0, installInfo.user); + ApplicationInfo applicationInfo = new PackageManagerHelper(context) + .getApplicationInfo(installInfo.packageName, installInfo.user, 0); // only if not yet installed if (applicationInfo == null) { PromiseAppInfo info = new PromiseAppInfo(installInfo); @@ -162,11 +163,8 @@ public class AllAppsList { * Add the icons for the supplied apk called packageName. */ public void addPackage(Context context, String packageName, UserHandle user) { - final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); - final List matches = launcherApps.getActivityList(packageName, - user); - - for (LauncherActivityInfo info : matches) { + for (LauncherActivityInfo info : context.getSystemService(LauncherApps.class) + .getActivityList(packageName, user)) { add(new AppInfo(context, info, user), info); } } @@ -212,9 +210,8 @@ public class AllAppsList { * Add and remove icons for this package which has been updated. */ public void updatePackage(Context context, String packageName, UserHandle user) { - final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); - final List matches = launcherApps.getActivityList(packageName, - user); + final List matches = context.getSystemService(LauncherApps.class) + .getActivityList(packageName, user); if (matches.size() > 0) { // Find disabled/removed activities and remove them from data and add them // to the removed list. diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 1c39d1f23c..6154e7ef84 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.Intent.ShortcutIconResource; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.CursorWrapper; @@ -33,17 +34,16 @@ import android.util.Log; import android.util.LongSparseArray; import com.android.launcher3.AppInfo; -import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.IconCache; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; -import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.logging.FileLog; import com.android.launcher3.util.ContentWriter; @@ -260,7 +260,7 @@ public class LoaderCursor extends CursorWrapper { Intent newIntent = new Intent(Intent.ACTION_MAIN, null); newIntent.addCategory(Intent.CATEGORY_LAUNCHER); newIntent.setComponent(componentName); - LauncherActivityInfo lai = LauncherAppsCompat.getInstance(mContext) + LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class) .resolveActivity(newIntent, user); if ((lai == null) && !allowMissingTarget) { Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName); diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 97cf846673..a29b7e1370 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -30,6 +30,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.ShortcutInfo; @@ -52,7 +53,6 @@ import com.android.launcher3.LauncherSettings; 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.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; @@ -105,7 +105,7 @@ public class LoaderTask implements Runnable { private final LoaderResults mResults; - private final LauncherAppsCompat mLauncherApps; + private final LauncherApps mLauncherApps; private final UserManagerCompat mUserManager; private final DeepShortcutManager mShortcutManager; private final PackageInstallerCompat mPackageInstaller; @@ -121,7 +121,7 @@ public class LoaderTask implements Runnable { mBgDataModel = dataModel; mResults = results; - mLauncherApps = LauncherAppsCompat.getInstance(mApp.getContext()); + mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class); mUserManager = UserManagerCompat.getInstance(mApp.getContext()); mShortcutManager = DeepShortcutManager.getInstance(mApp.getContext()); mPackageInstaller = PackageInstallerCompat.getInstance(mApp.getContext()); @@ -390,7 +390,7 @@ public class LoaderTask implements Runnable { // If there is no target package, its an implicit intent // (legacy shortcut) which is always valid boolean validTarget = TextUtils.isEmpty(targetPkg) || - mLauncherApps.isPackageEnabledForProfile(targetPkg, c.user); + mLauncherApps.isPackageEnabled(targetPkg, c.user); // If it's a deep shortcut, we'll use pinned shortcuts to restore it if (cn != null && validTarget && c.itemType @@ -399,7 +399,7 @@ public class LoaderTask implements Runnable { // component. // If the component is already present - if (mLauncherApps.isActivityEnabledForProfile(cn, c.user)) { + if (mLauncherApps.isActivityEnabled(cn, c.user)) { // no special handling necessary for this item c.markRestored(); } else { diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 7ea310c318..db63b7c251 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -16,10 +16,12 @@ package com.android.launcher3.model; import static com.android.launcher3.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; +import static com.android.launcher3.WorkspaceItemInfo.FLAG_RESTORED_ICON; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; import android.os.Process; import android.os.UserHandle; @@ -33,7 +35,6 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.SessionCommitReceiver; 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.config.FeatureFlags; import com.android.launcher3.icons.BitmapInfo; @@ -55,9 +56,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; -import static com.android.launcher3.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON; -import static com.android.launcher3.WorkspaceItemInfo.FLAG_RESTORED_ICON; - /** * Handles updates due to changes in package manager (app installed/updated/removed) * or when a user availability changes. @@ -221,8 +219,8 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { infoUpdated = true; } } else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) { - isTargetValid = LauncherAppsCompat.getInstance(context) - .isActivityEnabledForProfile(cn, mUser); + isTargetValid = context.getSystemService(LauncherApps.class) + .isActivityEnabled(cn, mUser); } if (si.hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) { if (updateWorkspaceItemIntent(context, si, packageName)) { @@ -305,9 +303,9 @@ public class PackageUpdatedTask extends BaseModelUpdateTask { // removedPackages is a super-set of removedComponents } else if (mOp == OP_UPDATE) { // Mark disabled packages in the broadcast to be removed - final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + final LauncherApps launcherApps = context.getSystemService(LauncherApps.class); for (int i=0; i> entry : mPackages.entrySet()) { UserHandle user = entry.getKey(); @@ -62,7 +62,7 @@ public class SdCardAvailableReceiver extends BroadcastReceiver { final ArrayList packagesUnavailable = new ArrayList<>(); for (String pkg : new HashSet<>(entry.getValue())) { - if (!launcherApps.isPackageEnabledForProfile(pkg, user)) { + if (!launcherApps.isPackageEnabled(pkg, user)) { if (pmHelper.isAppOnSdcard(pkg, user)) { packagesUnavailable.add(pkg); } else { diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java index e38529b3df..b442c421ee 100644 --- a/src/com/android/launcher3/model/WidgetItem.java +++ b/src/com/android/launcher3/model/WidgetItem.java @@ -8,8 +8,8 @@ import android.os.UserHandle; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; -import com.android.launcher3.compat.ShortcutConfigActivityInfo; import com.android.launcher3.icons.IconCache; +import com.android.launcher3.pm.ShortcutConfigActivityInfo; import com.android.launcher3.util.ComponentKey; import java.text.Collator; diff --git a/src/com/android/launcher3/pm/PackageInstallerCompat.java b/src/com/android/launcher3/pm/PackageInstallerCompat.java index 520c207c5f..c7b27d9308 100644 --- a/src/com/android/launcher3/pm/PackageInstallerCompat.java +++ b/src/com/android/launcher3/pm/PackageInstallerCompat.java @@ -31,11 +31,11 @@ import android.text.TextUtils; import com.android.launcher3.SessionCommitReceiver; import com.android.launcher3.Utilities; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.LooperExecutor; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; @@ -103,8 +103,8 @@ public class PackageInstallerCompat { public HashMap getActiveSessions() { HashMap activePackages = new HashMap<>(); for (SessionInfo info : getAllVerifiedSessions()) { - activePackages.put( - new PackageUserKey(info.getAppPackageName(), getUserHandle(info)), info); + activePackages.put(new PackageUserKey(info.getAppPackageName(), getUserHandle(info)), + info); } return activePackages; } @@ -141,9 +141,8 @@ public class PackageInstallerCompat { String pkg = sessionInfo.getInstallerPackageName(); synchronized (mSessionVerifiedMap) { if (!mSessionVerifiedMap.containsKey(pkg)) { - LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext); - boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg, - ApplicationInfo.FLAG_SYSTEM, getUserHandle(sessionInfo)) != null; + boolean hasSystemFlag = new PackageManagerHelper(mAppContext).getApplicationInfo( + pkg, getUserHandle(sessionInfo), ApplicationInfo.FLAG_SYSTEM) != null; mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag); } } @@ -190,8 +189,8 @@ public class PackageInstallerCompat { && sessionInfo.getAppIcon() != null && !TextUtils.isEmpty(sessionInfo.getAppLabel()) && !mPromiseIconIds.contains(sessionInfo.getSessionId()) - && LauncherAppsCompat.getInstance(mAppContext).getApplicationInfo( - sessionInfo.getAppPackageName(), 0, getUserHandle(sessionInfo)) == null) { + && new PackageManagerHelper(mAppContext).getApplicationInfo( + sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) { SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo); mPromiseIconIds.add(sessionInfo.getSessionId()); updatePromiseIconPrefs(); diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/pm/PinRequestHelper.java similarity index 59% rename from src/com/android/launcher3/compat/LauncherAppsCompatVO.java rename to src/com/android/launcher3/pm/PinRequestHelper.java index 5e13d00b74..68ea6c43ad 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java +++ b/src/com/android/launcher3/pm/PinRequestHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2014 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. @@ -14,83 +14,26 @@ * limitations under the License. */ -package com.android.launcher3.compat; +package com.android.launcher3.pm; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.PinItemRequest; -import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.os.Build; import android.os.Parcelable; -import android.os.Process; -import android.os.UserHandle; import androidx.annotation.Nullable; import com.android.launcher3.LauncherAppState; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO; import com.android.launcher3.icons.LauncherIcons; -import com.android.launcher3.util.PackageUserKey; -import java.util.ArrayList; -import java.util.List; - -@TargetApi(26) -public class LauncherAppsCompatVO extends LauncherAppsCompatVL { - - LauncherAppsCompatVO(Context context) { - super(context); - } - - @Override - public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) { - try { - ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user); - return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled - ? null : info; - } catch (PackageManager.NameNotFoundException e) { - return null; - } - } - - @Override - public List getCustomShortcutActivityList( - @Nullable PackageUserKey packageUser) { - List result = new ArrayList<>(); - UserHandle myUser = Process.myUserHandle(); - - final List users; - final String packageName; - if (packageUser == null) { - users = UserManagerCompat.getInstance(mContext).getUserProfiles(); - packageName = null; - } else { - users = new ArrayList<>(1); - users.add(packageUser.mUser); - packageName = packageUser.mPackageName; - } - for (UserHandle user : users) { - boolean ignoreTargetSdk = myUser.equals(user); - List activities = - mLauncherApps.getShortcutConfigActivityList(packageName, user); - for (LauncherActivityInfo activityInfo : activities) { - if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >= - Build.VERSION_CODES.O) { - result.add(new ShortcutConfigActivityInfoVO(activityInfo)); - } - } - } - - return result; - } +public class PinRequestHelper { /** * request.accept() will initiate the following flow: @@ -108,11 +51,11 @@ public class LauncherAppsCompatVO extends LauncherAppsCompatVL { * that (d) happens after model is updated. */ @Nullable + @TargetApi(Build.VERSION_CODES.O) public static WorkspaceItemInfo createWorkspaceItemFromPinItemRequest( Context context, final PinItemRequest request, final long acceptDelay) { - if (request != null && - request.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT && - request.isValid()) { + if (request != null && request.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT + && request.isValid()) { if (acceptDelay <= 0) { if (!request.accept()) { @@ -149,6 +92,7 @@ public class LauncherAppsCompatVO extends LauncherAppsCompatVL { } } + @TargetApi(Build.VERSION_CODES.O) public static PinItemRequest getPinItemRequest(Intent intent) { Parcelable extra = intent.getParcelableExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST); return extra instanceof PinItemRequest ? (PinItemRequest) extra : null; diff --git a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java similarity index 66% rename from src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java rename to src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java index ace5691994..0922e411c5 100644 --- a/src/com/android/launcher3/compat/ShortcutConfigActivityInfo.java +++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java @@ -14,29 +14,40 @@ * limitations under the License. */ -package com.android.launcher3.compat; +package com.android.launcher3.pm; import android.annotation.TargetApi; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Process; import android.os.UserHandle; import android.util.Log; import android.widget.Toast; -import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.ComponentWithLabel; -import com.android.launcher3.icons.IconCache; +import androidx.annotation.Nullable; + import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.icons.ComponentWithLabel; +import com.android.launcher3.icons.IconCache; +import com.android.launcher3.util.PackageUserKey; + +import java.util.ArrayList; +import java.util.List; /** * Wrapper class for representing a shortcut configure activity. @@ -87,9 +98,9 @@ public abstract class ShortcutConfigActivityInfo implements ComponentWithLabel { Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); } catch (SecurityException e) { Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); - Log.e(TAG, "Launcher does not have the permission to launch " + intent + - ". Make sure to create a MAIN intent-filter for the corresponding activity " + - "or use the exported attribute for this activity.", e); + Log.e(TAG, "Launcher does not have the permission to launch " + intent + + ". Make sure to create a MAIN intent-filter for the corresponding activity " + + "or use the exported attribute for this activity.", e); } return false; } @@ -106,7 +117,7 @@ public abstract class ShortcutConfigActivityInfo implements ComponentWithLabel { private final ActivityInfo mInfo; - public ShortcutConfigActivityInfoVL(ActivityInfo info) { + ShortcutConfigActivityInfoVL(ActivityInfo info) { super(new ComponentName(info.packageName, info.name), Process.myUserHandle()); mInfo = info; } @@ -158,4 +169,46 @@ public abstract class ShortcutConfigActivityInfo implements ComponentWithLabel { } } } + + public static List queryList( + Context context, @Nullable PackageUserKey packageUser) { + List result = new ArrayList<>(); + UserHandle myUser = Process.myUserHandle(); + + if (Utilities.ATLEAST_OREO) { + final List users; + final String packageName; + if (packageUser == null) { + users = UserManagerCompat.getInstance(context).getUserProfiles(); + packageName = null; + } else { + users = new ArrayList<>(1); + users.add(packageUser.mUser); + packageName = packageUser.mPackageName; + } + LauncherApps launcherApps = context.getSystemService(LauncherApps.class); + for (UserHandle user : users) { + boolean ignoreTargetSdk = myUser.equals(user); + for (LauncherActivityInfo activityInfo : + launcherApps.getShortcutConfigActivityList(packageName, user)) { + if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.O) { + result.add(new ShortcutConfigActivityInfoVO(activityInfo)); + } + } + } + } else { + if (packageUser == null || packageUser.mUser.equals(myUser)) { + Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT); + if (packageUser != null) { + intent.setPackage(packageUser.mPackageName); + } + for (ResolveInfo info : + context.getPackageManager().queryIntentActivities(intent, 0)) { + result.add(new ShortcutConfigActivityInfoVL(info.activityInfo)); + } + } + } + return result; + } } diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index ef4307ec59..7b4e0c6ede 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -34,6 +35,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.PatternMatcher; +import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; @@ -46,8 +48,8 @@ import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.PromiseAppInfo; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.compat.LauncherAppsCompat; import java.net.URISyntaxException; import java.util.List; @@ -61,12 +63,12 @@ public class PackageManagerHelper { private final Context mContext; private final PackageManager mPm; - private final LauncherAppsCompat mLauncherApps; + private final LauncherApps mLauncherApps; public PackageManagerHelper(Context context) { mContext = context; mPm = context.getPackageManager(); - mLauncherApps = LauncherAppsCompat.getInstance(context); + mLauncherApps = context.getSystemService(LauncherApps.class); } /** @@ -74,8 +76,8 @@ public class PackageManagerHelper { * guarantee that the app is on SD card. */ public boolean isAppOnSdcard(String packageName, UserHandle user) { - ApplicationInfo info = mLauncherApps.getApplicationInfo( - packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, user); + ApplicationInfo info = getApplicationInfo( + packageName, user, PackageManager.MATCH_UNINSTALLED_PACKAGES); return info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } @@ -84,10 +86,47 @@ public class PackageManagerHelper { * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}. */ public boolean isAppSuspended(String packageName, UserHandle user) { - ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, 0, user); + ApplicationInfo info = getApplicationInfo(packageName, user, 0); return info != null && isAppSuspended(info); } + /** + * Returns the application info for the provided package or null + */ + public ApplicationInfo getApplicationInfo(String packageName, UserHandle user, int flags) { + if (Utilities.ATLEAST_OREO) { + try { + ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user); + return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled + ? null : info; + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } else { + final boolean isPrimaryUser = Process.myUserHandle().equals(user); + if (!isPrimaryUser && (flags == 0)) { + // We are looking for an installed app on a secondary profile. Prior to O, the only + // entry point for work profiles is through the LauncherActivity. + List activityList = + mLauncherApps.getActivityList(packageName, user); + return activityList.size() > 0 ? activityList.get(0).getApplicationInfo() : null; + } + try { + ApplicationInfo info = mPm.getApplicationInfo(packageName, flags); + // There is no way to check if the app is installed for managed profile. But for + // primary profile, we can still have this check. + if (isPrimaryUser && ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) + || !info.enabled) { + return null; + } + return info; + } catch (PackageManager.NameNotFoundException e) { + // Package not found + return null; + } + } + } + public boolean isSafeMode() { return mContext.getPackageManager().isSafeMode(); } @@ -202,8 +241,7 @@ public class PackageManagerHelper { } if (componentName != null) { try { - mLauncherApps.showAppDetailsForProfile( - componentName, info.user, sourceBounds, opts); + mLauncherApps.startAppDetailsActivity(componentName, info.user, sourceBounds, opts); } catch (SecurityException | ActivityNotFoundException e) { Toast.makeText(mContext, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Unable to launch settings", e); diff --git a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java new file mode 100644 index 0000000000..465a0e8b05 --- /dev/null +++ b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java @@ -0,0 +1,48 @@ +/* + * 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 android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import java.util.function.Consumer; + +public class SimpleBroadcastReceiver extends BroadcastReceiver { + + private final Consumer mIntentConsumer; + + public SimpleBroadcastReceiver(Consumer intentConsumer) { + mIntentConsumer = intentConsumer; + } + + @Override + public void onReceive(Context context, Intent intent) { + mIntentConsumer.accept(intent); + } + + /** + * Helper method to register multiple actions + */ + public void register(Context context, String... actions) { + IntentFilter filter = new IntentFilter(); + for (String action : actions) { + filter.addAction(action); + } + context.registerReceiver(this, filter); + } +} diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java index 62b6903f7a..6e21a41b27 100644 --- a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java +++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java @@ -16,7 +16,7 @@ package com.android.launcher3.widget; import com.android.launcher3.PendingAddItemInfo; -import com.android.launcher3.compat.ShortcutConfigActivityInfo; +import com.android.launcher3.pm.ShortcutConfigActivityInfo; /** * Meta data used for late binding of the short cuts. diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java index 0f6ad27130..b8af8ed85b 100644 --- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java +++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java @@ -3,6 +3,8 @@ package com.android.launcher3.model; import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER; +import static com.android.launcher3.pm.ShortcutConfigActivityInfo.queryList; + import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.pm.PackageManager; @@ -10,6 +12,8 @@ import android.os.Process; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.Nullable; + import com.android.launcher3.AppFilter; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; @@ -17,11 +21,10 @@ import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.compat.ShortcutConfigActivityInfo; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.ComponentWithLabel; import com.android.launcher3.icons.IconCache; +import com.android.launcher3.pm.ShortcutConfigActivityInfo; import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; @@ -37,8 +40,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import androidx.annotation.Nullable; - /** * Widgets data model that is used by the adapters of the widget views and controllers. * @@ -106,8 +107,8 @@ public class WidgetsModel { } // Shortcuts - for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context) - .getCustomShortcutActivityList(packageUser)) { + for (ShortcutConfigActivityInfo info : + queryList(context, packageUser)) { widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm)); updatedItems.add(info); } diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 64df8e0e95..7029ad586c 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -1,29 +1,5 @@ package com.android.launcher3.model; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.database.MatrixCursor; -import android.graphics.Bitmap; -import android.os.Process; -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.IconCache; -import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.compat.LauncherAppsCompat; -import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.util.PackageManagerHelper; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static com.android.launcher3.LauncherSettings.Favorites.INTENT; import static com.android.launcher3.LauncherSettings.Favorites.CELLX; import static com.android.launcher3.LauncherSettings.Favorites.CELLY; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER; @@ -32,6 +8,7 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT import static com.android.launcher3.LauncherSettings.Favorites.ICON; import static com.android.launcher3.LauncherSettings.Favorites.ICON_PACKAGE; import static com.android.launcher3.LauncherSettings.Favorites.ICON_RESOURCE; +import static com.android.launcher3.LauncherSettings.Favorites.INTENT; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; @@ -40,15 +17,41 @@ import static com.android.launcher3.LauncherSettings.Favorites.RESTORED; import static com.android.launcher3.LauncherSettings.Favorites.SCREEN; import static com.android.launcher3.LauncherSettings.Favorites.TITLE; import static com.android.launcher3.LauncherSettings.Favorites._ID; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; + import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.LauncherApps; +import android.database.MatrixCursor; +import android.graphics.Bitmap; +import android.os.Process; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.icons.IconCache; +import com.android.launcher3.util.PackageManagerHelper; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + /** * Tests for {@link LoaderCursor} */ @@ -62,7 +65,7 @@ public class LoaderCursorTest { private MatrixCursor mCursor; private InvariantDeviceProfile mIDP; private Context mContext; - private LauncherAppsCompat mLauncherApps; + private LauncherApps mLauncherApps; private LoaderCursor mLoaderCursor; @@ -81,7 +84,7 @@ public class LoaderCursorTest { when(mMockApp.getIconCache()).thenReturn(mMockIconCache); when(mMockApp.getInvariantDeviceProfile()).thenReturn(mIDP); when(mMockApp.getContext()).thenReturn(mContext); - mLauncherApps = LauncherAppsCompat.getInstance(mContext); + mLauncherApps = mContext.getSystemService(LauncherApps.class); mLoaderCursor = new LoaderCursor(mCursor, mMockApp); mLoaderCursor.allUsers.put(0, Process.myUserHandle()); diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 63657dd9cb..17763d0a2d 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -34,6 +34,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.os.Process; import android.os.RemoteException; @@ -53,7 +54,6 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.Utilities; -import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.tapl.TestHelpers; @@ -343,9 +343,8 @@ public abstract class AbstractLauncherUiTest { } protected LauncherActivityInfo getSettingsApp() { - return LauncherAppsCompat.getInstance(mTargetContext) - .getActivityList("com.android.settings", - Process.myUserHandle()).get(0); + return mTargetContext.getSystemService(LauncherApps.class) + .getActivityList("com.android.settings", Process.myUserHandle()).get(0); } /** From 387279d9385b520e20ba7c6e10efb6c64de130a0 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Wed, 14 Aug 2019 15:01:53 -0700 Subject: [PATCH 074/109] Live tile should switch to screenshot before finishing recents animation Fixes: 139439373 Test: Launch a new app from shortcuts in Overview mode. Make sure the live tile stays put (no hole). Same with touching empty space in Overview to go home. Change-Id: I6cacf2842e21f9856d0021cea9fddf4f870f09f0 --- .../uioverrides/RecentsUiFactory.java | 2 +- .../uioverrides/RecentsUiFactory.java | 15 ++-- .../src/com/android/quickstep/ViewUtils.java | 74 +++++++++++++++++++ .../WindowTransformSwipeHandler.java | 48 ++++-------- .../quickstep/views/LauncherRecentsView.java | 7 +- .../android/quickstep/views/RecentsView.java | 29 +++++++- .../quickstep/views/TaskThumbnailView.java | 29 ++++++-- .../com/android/quickstep/views/TaskView.java | 1 - src/com/android/launcher3/Launcher.java | 2 +- .../launcher3/uioverrides/UiFactory.java | 3 +- 10 files changed, 160 insertions(+), 50 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/ViewUtils.java diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index ae8fd82241..f2aa842d12 100644 --- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -89,5 +89,5 @@ public abstract class RecentsUiFactory { return RotationMode.NORMAL; } - public static void clearSwipeSharedState(boolean finishAnimation) {} + public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index 46e883aca3..2f8af44663 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -18,6 +18,7 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Context; @@ -196,11 +197,15 @@ public abstract class RecentsUiFactory { return new RecentsViewStateController(launcher); } - /** - * Clears the swipe shared state for the current swipe gesture. - */ - public static void clearSwipeSharedState(boolean finishAnimation) { - TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation); + /** Clears the swipe shared state for the current swipe gesture. */ + public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + launcher.getOverviewPanel().switchToScreenshot( + () -> TouchInteractionService.getSwipeSharedState().clearAllState( + finishAnimation)); + } else { + TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation); + } } /** diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/ViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/ViewUtils.java new file mode 100644 index 0000000000..cbb6ad4188 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/ViewUtils.java @@ -0,0 +1,74 @@ +/* + * 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.quickstep; + +import android.graphics.Canvas; +import android.view.View; + +import com.android.systemui.shared.system.WindowCallbacksCompat; + +import java.util.function.BooleanSupplier; + +/** + * Utility class for helpful methods related to {@link View} objects. + */ +public class ViewUtils { + + /** See {@link #postDraw(View, Runnable, BooleanSupplier)}} */ + public static boolean postDraw(View view, Runnable onFinishRunnable) { + return postDraw(view, onFinishRunnable, () -> false); + } + + /** + * Inject some addition logic in order to make sure that the view is updated smoothly post + * draw, and allow addition task to be run after view update. + * + * @param onFinishRunnable runnable to be run right after the view finishes drawing. + */ + public static boolean postDraw(View view, Runnable onFinishRunnable, BooleanSupplier canceled) { + // Defer finishing the animation until the next launcher frame with the + // new thumbnail + return new WindowCallbacksCompat(view) { + // The number of frames to defer until we actually finish the animation + private int mDeferFrameCount = 2; + + @Override + public void onPostDraw(Canvas canvas) { + // If we were cancelled after this was attached, do not update + // the state. + if (canceled.getAsBoolean()) { + detach(); + return; + } + + if (mDeferFrameCount > 0) { + mDeferFrameCount--; + // Workaround, detach and reattach to invalidate the root node for + // another draw + detach(); + attach(); + view.invalidate(); + return; + } + + if (onFinishRunnable != null) { + onFinishRunnable.run(); + } + detach(); + } + }.attach(); + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index db8eb27533..c03457948c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -45,7 +45,6 @@ import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.Intent; -import android.graphics.Canvas; import android.graphics.PointF; import android.graphics.RectF; import android.os.Build; @@ -90,12 +89,10 @@ import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.LatencyTrackerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.WindowCallbacksCompat; @TargetApi(Build.VERSION_CODES.O) public class WindowTransformSwipeHandler - extends BaseSwipeUpHandler - implements OnApplyWindowInsetsListener { + extends BaseSwipeUpHandler implements OnApplyWindowInsetsListener { private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName(); private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null; @@ -1007,6 +1004,10 @@ public class WindowTransformSwipeHandler } } + public boolean isCanceled() { + return mCanceled; + } + @UiThread private void resumeLastTask() { mRecentsAnimationWrapper.finish(false /* toRecents */, null); @@ -1099,14 +1100,21 @@ public class WindowTransformSwipeHandler } private void switchToScreenshot() { + SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController(); if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + if (controller != null) { + // Update the screenshot of the task + if (mTaskSnapshot == null) { + mTaskSnapshot = controller.screenshotTask(mRunningTaskId); + } + mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot, false /* refreshNow */); + } setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); } else if (!mRecentsAnimationWrapper.hasTargets()) { // If there are no targets, then we don't need to capture anything setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); } else { boolean finishTransitionPosted = false; - SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController(); if (controller != null) { // Update the screenshot of the task if (mTaskSnapshot == null) { @@ -1123,34 +1131,8 @@ public class WindowTransformSwipeHandler if (taskView != null && !mCanceled) { // Defer finishing the animation until the next launcher frame with the // new thumbnail - finishTransitionPosted = new WindowCallbacksCompat(taskView) { - - // The number of frames to defer until we actually finish the animation - private int mDeferFrameCount = 2; - - @Override - public void onPostDraw(Canvas canvas) { - // If we were cancelled after this was attached, do not update - // the state. - if (mCanceled) { - detach(); - return; - } - - if (mDeferFrameCount > 0) { - mDeferFrameCount--; - // Workaround, detach and reattach to invalidate the root node for - // another draw - detach(); - attach(); - taskView.invalidate(); - return; - } - - setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); - detach(); - } - }.attach(); + finishTransitionPosted = ViewUtils.postDraw(taskView, + () -> setStateOnUiThread(STATE_SCREENSHOT_CAPTURED), this::isCanceled); } } if (!finishTransitionPosted) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 0f9fc17aa6..4c308fb8c0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -78,7 +78,12 @@ public class LauncherRecentsView extends RecentsView implements StateL @Override public void startHome() { - mActivity.getStateManager().goToState(NORMAL); + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + switchToScreenshot(() -> finishRecentsAnimation(true /* toRecents */, + () -> mActivity.getStateManager().goToState(NORMAL))); + } else { + mActivity.getStateManager().goToState(NORMAL); + } } @Override 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 554f4372c3..29e93aa8d3 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 @@ -107,6 +107,7 @@ import com.android.quickstep.RecentsModel; import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; +import com.android.quickstep.ViewUtils; import com.android.quickstep.util.ClipAnimationHelper; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -380,14 +381,23 @@ public abstract class RecentsView extends PagedView impl return null; } - public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) { + /** + * Update the thumbnail of the task. + * @param refreshNow Refresh immediately if it's true. + */ + public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData, boolean refreshNow) { TaskView taskView = getTaskView(taskId); if (taskView != null) { - taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData); + taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData, refreshNow); } return taskView; } + /** See {@link #updateThumbnail(int, ThumbnailData, boolean)} */ + public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) { + return updateThumbnail(taskId, thumbnailData, true /* refreshNow */); + } + @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); @@ -1819,4 +1829,19 @@ public abstract class RecentsView extends PagedView impl final WindowInsets insets = getRootWindowInsets(); return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight()); } + + /** If it's in the live tile mode, switch the running task into screenshot mode. */ + public void switchToScreenshot(Runnable onFinishRunnable) { + TaskView taskView = getRunningTaskView(); + if (taskView == null) { + if (onFinishRunnable != null) { + onFinishRunnable.run(); + } + return; + } + + taskView.setShowScreenshot(true); + taskView.getThumbnail().refresh(); + ViewUtils.postDraw(taskView, onFinishRunnable); + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java index 5799c0164f..adeb97425e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java @@ -134,16 +134,35 @@ public class TaskThumbnailView extends View implements PluginListener startActivitySafely(v, intent, item, sourceContainer)); - UiFactory.clearSwipeSharedState(true /* finishAnimation */); + UiFactory.clearSwipeSharedState(this, true /* finishAnimation */); return true; } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 467ae02d5c..6d9ed88e08 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -96,7 +96,8 @@ public class UiFactory { public static void resetPendingActivityResults(Launcher launcher, int requestCode) { } - public static void clearSwipeSharedState(boolean finishAnimation) {} + /** No-op. */ + public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { } public static Person[] getPersons(ShortcutInfo si) { return Utilities.EMPTY_PERSON_ARRAY; From 233afe98e92935e2f5cf0813994a84fdc7763b4d Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 2 Oct 2019 17:10:02 -0700 Subject: [PATCH 075/109] Dump view hierarchy before swiping to home Bug: 141864547 Change-Id: Ifd444c4516f7f27b0dc19c0faa1d4c8716d2254a --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 2e9cb81f0c..24d4964d50 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -558,6 +558,8 @@ public final class LauncherInstrumentation { if (hasLauncherObject(WORKSPACE_RES_ID)) { log(action = "already at home"); } else { + log("Hierarchy before swiping up to home"); + dumpViewHierarchy(); log(action = "swiping up to home from " + getVisibleStateMessage()); final int finalState = mDevice.hasObject(By.pkg(getLauncherPackageName())) ? NORMAL_STATE_ORDINAL : BACKGROUND_APP_STATE_ORDINAL; From d625e49552a96d384745174ff6a137f1dd7837b7 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 2 Oct 2019 11:25:44 -0700 Subject: [PATCH 076/109] include integration test for adding shortcut widget this integration test help us catching app crashes when adding shortcut widgets to the workplace. see b/141568904 for more context. Bug: 141934188 Change-Id: I4d33d6127793efe2071d0d146aef24db6b676360 --- tests/AndroidManifest-common.xml | 6 ++ .../ShortcutWidgetConfigActivity.java | 62 +++++++++++++++++++ .../launcher3/ui/TaplTestsLauncher3.java | 9 +++ 3 files changed, 77 insertions(+) create mode 100644 tests/src/com/android/launcher3/testcomponent/ShortcutWidgetConfigActivity.java diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index c6f55a7178..6802152c76 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -62,6 +62,12 @@ + + + + + + Date: Fri, 27 Sep 2019 16:29:32 -0700 Subject: [PATCH 077/109] Fix the issue talkback feedback doesn't say anything when user long press on an app icon. When user long press on an app icon, the a11y focus event wasn't properly triggered on the container of deep shortcut, which is why there wasn't any talkback feedback after long press on an app icon. Bug: 140786694 Change-Id: Ib38db147faa5a163985f1ed74beec04c588b022c --- src/com/android/launcher3/AbstractFloatingView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index 8fddf3cff9..af2cdc3ed0 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -16,7 +16,6 @@ package com.android.launcher3; -import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; @@ -30,6 +29,7 @@ import android.util.AttributeSet; import android.util.Pair; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.LinearLayout; import androidx.annotation.IntDef; @@ -171,7 +171,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch targetInfo.first, TYPE_WINDOW_STATE_CHANGED, targetInfo.second); if (mIsOpen) { - sendAccessibilityEvent(TYPE_VIEW_FOCUSED); + performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); } ActivityContext.lookupContext(getContext()).getDragLayer() .sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED); From d7fdcab612d9c8136283ea432a24800a9cdbfdc8 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 3 Oct 2019 10:15:30 -0700 Subject: [PATCH 078/109] correct naming and add comments for test case of custom shortcut. Bug: 141934188 Change-Id: I69ce5f05214df10e2a376ff68c713efe8874df15 --- tests/AndroidManifest-common.xml | 2 +- ...ctivity.java => CustomShortcutConfigActivity.java} | 6 +++++- .../com/android/launcher3/ui/TaplTestsLauncher3.java | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) rename tests/src/com/android/launcher3/testcomponent/{ShortcutWidgetConfigActivity.java => CustomShortcutConfigActivity.java} (91%) diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index 6802152c76..ffa90b9c5b 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -62,7 +62,7 @@ - + diff --git a/tests/src/com/android/launcher3/testcomponent/ShortcutWidgetConfigActivity.java b/tests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java similarity index 91% rename from tests/src/com/android/launcher3/testcomponent/ShortcutWidgetConfigActivity.java rename to tests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java index f9d5f2d435..b673faa6f3 100644 --- a/tests/src/com/android/launcher3/testcomponent/ShortcutWidgetConfigActivity.java +++ b/tests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java @@ -27,7 +27,11 @@ import com.android.launcher3.R; import java.util.UUID; -public class ShortcutWidgetConfigActivity extends BaseTestingActivity { +/** + * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it. + * Custom shortcuts are replaced by deep shortcuts after api 25. + */ +public class CustomShortcutConfigActivity extends BaseTestingActivity { @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index 38dba16280..709822bbbf 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -342,10 +342,17 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { } } + /** + * Test dragging a custom shortcut to the workspace and launch it. + * + * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it. + * Custom shortcuts are replaced by deep shortcuts after api 25. + */ @Test - public void testDragShortcutWidget() { + @PortraitLandscape + public void testDragCustomShortcut() { mLauncher.getWorkspace().openAllWidgets() - .getWidget("com.android.launcher3.testcomponent.ShortcutWidgetConfigActivity") + .getWidget("com.android.launcher3.testcomponent.CustomShortcutConfigActivity") .dragToWorkspace(); mLauncher.getWorkspace().getWorkspaceAppIcon("Shortcut") .launch(getAppPackageName()); From a9d870828c0edc07b860aa120fe50e7ad47b5926 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 3 Oct 2019 13:34:28 -0700 Subject: [PATCH 079/109] resolve merge conflicts of 08776ada1e37c4b424893306c058b1de9f85903f to ub-launcher3-qt-future-dev Bug: None Test: I solemnly swear I tested this conflict resolution. Change-Id: I9a3b0f67ee874b5ec4ad67f41a46ec7876d19082 From cdb72146e85019ba2fd17fe8667f930e515913eb Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Mon, 22 Jul 2019 14:01:34 -0700 Subject: [PATCH 080/109] Handle app switch in Overview - Transfer screenshot from WM to launcher when recents animation gets cancelled due to stack order change - Transform two live windows when app open animation happens from recents Fixes: 139258979 Fixes: 139259253 Test: switch task in overview Change-Id: I80bafb8d45b9250fda937223254e365596a7f538 --- .../AppToOverviewAnimationProvider.java | 6 +- .../android/quickstep/BaseSwipeUpHandler.java | 19 ++- .../LauncherActivityControllerHelper.java | 21 +++ .../android/quickstep/SwipeSharedState.java | 25 +++- .../com/android/quickstep/TaskViewUtils.java | 41 +++++- .../WindowTransformSwipeHandler.java | 2 +- .../DeviceLockedInputConsumer.java | 10 +- .../FallbackNoButtonInputConsumer.java | 2 +- .../quickstep/util/ClipAnimationHelper.java | 139 +++++++++++------- .../util/RecentsAnimationListenerSet.java | 16 +- .../util/SwipeAnimationTargetSet.java | 6 +- .../quickstep/views/LauncherRecentsView.java | 25 ++-- .../android/quickstep/views/RecentsView.java | 13 +- .../quickstep/ActivityControlHelper.java | 3 + 14 files changed, 227 insertions(+), 101 deletions(-) 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 b939898e1c..89c34d34a8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -148,8 +148,10 @@ final class AppToOverviewAnimationProvider imple valueAnimator.setDuration(RECENTS_LAUNCH_DURATION); valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); valueAnimator.addUpdateListener((v) -> { - params.setProgress((float) v.getAnimatedValue()); - clipHelper.applyTransform(targetSet, params); + params.setProgress((float) v.getAnimatedValue()) + .setTargetSet(targetSet) + .setLauncherOnTop(true); + clipHelper.applyTransform(params); }); if (targetSet.isAnimatingHome()) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index d524b5d25c..ed6a7e8499 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -367,9 +367,12 @@ public abstract class BaseSwipeUpHandler { + if (mRecentsAnimationCanceledCallback != null) { + mRecentsAnimationCanceledCallback.run(); + } + clearAnimationState(); + }); + } else { + clearAnimationState(); + } + } + + public void setRecentsAnimationCanceledCallback(Runnable callback) { + mRecentsAnimationCanceledCallback = callback; + } + + private void clearAnimationState() { clearAnimationTarget(); mLastAnimationCancelled = true; mLastAnimationRunning = false; + mRecentsAnimationCanceledCallback = null; } private void clearListenerState(boolean finishAnimation) { @@ -127,7 +148,7 @@ public class SwipeSharedState implements SwipeAnimationListener { if (mLastAnimationTarget != null) { listener.onRecentsAnimationStart(mLastAnimationTarget); } else if (mLastAnimationCancelled) { - listener.onRecentsAnimationCanceled(); + listener.onRecentsAnimationCanceled(null); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java index 00fa0f2745..b4a7996fb7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java @@ -17,6 +17,7 @@ package com.android.quickstep; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; +import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; import android.animation.Animator; @@ -38,6 +39,11 @@ import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; +import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Utility class for helpful methods related to {@link TaskView} objects and their tasks. @@ -115,12 +121,13 @@ public final class TaskViewUtils { RemoteAnimationTargetCompat[] wallpaperTargets, final ClipAnimationHelper inOutHelper) { SyncRtSurfaceTransactionApplierCompat applier = new SyncRtSurfaceTransactionApplierCompat(v); - ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams() - .setSyncTransactionApplier(applier); - final RemoteAnimationTargetSet targetSet = new RemoteAnimationTargetSet(appTargets, wallpaperTargets, MODE_OPENING); targetSet.addDependentTransactionApplier(applier); + ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams() + .setSyncTransactionApplier(applier) + .setTargetSet(targetSet) + .setLauncherOnTop(true); final RecentsView recentsView = v.getRecentsView(); final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); @@ -152,7 +159,33 @@ public final class TaskViewUtils { public void onUpdate(float percent) { // TODO: Take into account the current fullscreen progress for animating the insets params.setProgress(1 - percent); - RectF taskBounds = inOutHelper.applyTransform(targetSet, params); + RectF taskBounds; + if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + List surfaceParamsList = new ArrayList<>(); + // Append the surface transform params for the app that's being opened. + Collections.addAll(surfaceParamsList, inOutHelper.getSurfaceParams(params)); + + ClipAnimationHelper liveTileClipAnimationHelper = + v.getRecentsView().getClipAnimationHelper(); + if (liveTileClipAnimationHelper != null) { + // Append the surface transform params for the live tile app. + ClipAnimationHelper.TransformParams liveTileParams = + v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */); + if (liveTileParams != null) { + Collections.addAll(surfaceParamsList, + liveTileClipAnimationHelper.getSurfaceParams(liveTileParams)); + } + } + // Apply surface transform using the surface params list. + ClipAnimationHelper.applySurfaceParams(params.syncTransactionApplier, + surfaceParamsList.toArray(new SurfaceParams[surfaceParamsList.size()])); + // Get the task bounds for the app that's being opened after surface transform + // update. + taskBounds = inOutHelper.updateCurrentRect(params); + } else { + taskBounds = inOutHelper.applyTransform(params); + } + int taskIndex = recentsView.indexOfChild(v); int centerTaskIndex = recentsView.getCurrentPage(); boolean parallaxCenterAndAdjacentTask = taskIndex != centerTaskIndex; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index c03457948c..7e99366a82 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -614,7 +614,7 @@ public class WindowTransformSwipeHandler } @Override - public void onRecentsAnimationCanceled() { + public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { mRecentsAnimationWrapper.setController(null); mActivityInitListener.unregister(); setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index b24c788107..d11afaf080 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -46,6 +46,7 @@ import com.android.quickstep.SwipeSharedState; import com.android.quickstep.util.ClipAnimationHelper; import com.android.quickstep.util.RecentsAnimationListenerSet; import com.android.quickstep.util.SwipeAnimationTargetSet; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -155,9 +156,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, float dy = Math.max(mTouchDown.y - y, 0); mProgress = dy / mDisplaySize.y; mTransformParams.setProgress(mProgress); - if (mTargetSet != null) { - mClipAnimationHelper.applyTransform(mTargetSet, mTransformParams); - } + mClipAnimationHelper.applyTransform(mTransformParams); } break; } @@ -228,13 +227,14 @@ public class DeviceLockedInputConsumer implements InputConsumer, Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN); displaySize.offsetTo(displaySize.left, 0); mClipAnimationHelper.updateTargetRect(displaySize); - mClipAnimationHelper.applyTransform(mTargetSet, mTransformParams); + mTransformParams.setTargetSet(mTargetSet).setLauncherOnTop(true); + mClipAnimationHelper.applyTransform(mTransformParams); mStateCallback.setState(STATE_TARGET_RECEIVED); } @Override - public void onRecentsAnimationCanceled() { + public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { mTargetSet = null; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 6275d21dc0..629d240225 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -427,7 +427,7 @@ public class FallbackNoButtonInputConsumer extends } @Override - public void onRecentsAnimationCanceled() { + public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { mRecentsAnimationWrapper.setController(null); setStateOnUiThread(STATE_HANDLER_INVALIDATED); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java index cae273a164..587e9f24a4 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -157,12 +157,75 @@ public class ClipAnimationHelper { mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode; } - public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params) { - return applyTransform(targetSet, params, true /* launcherOnTop */); + public RectF applyTransform(TransformParams params) { + SurfaceParams[] surfaceParams = getSurfaceParams(params); + if (surfaceParams == null) { + return null; + } + applySurfaceParams(params.syncTransactionApplier, surfaceParams); + return params.currentRect; } - public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params, - boolean launcherOnTop) { + public SurfaceParams[] getSurfaceParams(TransformParams params) { + if (params.targetSet == null) { + return null; + } + + float progress = params.progress; + updateCurrentRect(params); + + SurfaceParams[] surfaceParams = new SurfaceParams[params.targetSet.unfilteredApps.length]; + for (int i = 0; i < params.targetSet.unfilteredApps.length; i++) { + RemoteAnimationTargetCompat app = params.targetSet.unfilteredApps[i]; + mTmpMatrix.setTranslate(app.position.x, app.position.y); + Rect crop = mTmpRect; + crop.set(app.sourceContainerBounds); + crop.offsetTo(0, 0); + float alpha; + int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers); + float cornerRadius = 0f; + float scale = Math.max(params.currentRect.width(), mTargetRect.width()) / crop.width(); + if (app.mode == params.targetSet.targetMode) { + alpha = mTaskAlphaCallback.getAlpha(app, params.targetAlpha); + if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + mTmpMatrix.setRectToRect(mSourceRect, params.currentRect, ScaleToFit.FILL); + mTmpMatrix.postTranslate(app.position.x, app.position.y); + mClipRectF.roundOut(crop); + if (mSupportsRoundedCornersOnWindows) { + if (params.cornerRadius > -1) { + cornerRadius = params.cornerRadius; + scale = params.currentRect.width() / crop.width(); + } else { + float windowCornerRadius = mUseRoundedCornersOnWindows + ? mWindowCornerRadius : 0; + cornerRadius = Utilities.mapRange(progress, windowCornerRadius, + mTaskCornerRadius); + } + mCurrentCornerRadius = cornerRadius; + } + } else if (params.targetSet.hasRecents) { + // If home has a different target then recents, reverse anim the + // home target. + alpha = 1 - (progress * params.targetAlpha); + } + } else { + alpha = mBaseAlphaCallback.getAlpha(app, progress); + if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.launcherOnTop) { + crop = null; + layer = Integer.MAX_VALUE; + } + } + + // Since radius is in Surface space, but we draw the rounded corners in screen space, we + // have to undo the scale. + surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer, + cornerRadius / scale); + } + applySurfaceParams(params.syncTransactionApplier, surfaceParams); + return surfaceParams; + } + + public RectF updateCurrentRect(TransformParams params) { float progress = params.progress; if (params.currentRect == null) { RectF currentRect; @@ -183,55 +246,6 @@ public class ClipAnimationHelper { mSourceStackBounds.height() - (sourceWindowClipInsets.bottom * progress); params.setCurrentRectAndTargetAlpha(currentRect, 1); } - - SurfaceParams[] surfaceParams = new SurfaceParams[targetSet.unfilteredApps.length]; - for (int i = 0; i < targetSet.unfilteredApps.length; i++) { - RemoteAnimationTargetCompat app = targetSet.unfilteredApps[i]; - mTmpMatrix.setTranslate(app.position.x, app.position.y); - Rect crop = mTmpRect; - crop.set(app.sourceContainerBounds); - crop.offsetTo(0, 0); - float alpha; - int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers); - float cornerRadius = 0f; - float scale = Math.max(params.currentRect.width(), mTargetRect.width()) / crop.width(); - if (app.mode == targetSet.targetMode) { - alpha = mTaskAlphaCallback.getAlpha(app, params.targetAlpha); - if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { - mTmpMatrix.setRectToRect(mSourceRect, params.currentRect, ScaleToFit.FILL); - mTmpMatrix.postTranslate(app.position.x, app.position.y); - mClipRectF.roundOut(crop); - if (mSupportsRoundedCornersOnWindows) { - if (params.cornerRadius > -1) { - cornerRadius = params.cornerRadius; - scale = params.currentRect.width() / crop.width(); - } else { - float windowCornerRadius = mUseRoundedCornersOnWindows - ? mWindowCornerRadius : 0; - cornerRadius = Utilities.mapRange(progress, windowCornerRadius, - mTaskCornerRadius); - } - mCurrentCornerRadius = cornerRadius; - } - } else if (targetSet.hasRecents) { - // If home has a different target then recents, reverse anim the - // home target. - alpha = 1 - (progress * params.targetAlpha); - } - } else { - alpha = mBaseAlphaCallback.getAlpha(app, progress); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && launcherOnTop) { - crop = null; - layer = Integer.MAX_VALUE; - } - } - - // Since radius is in Surface space, but we draw the rounded corners in screen space, we - // have to undo the scale. - surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer, - cornerRadius / scale); - } - applySurfaceParams(params.syncTransactionApplier, surfaceParams); return params.currentRect; } @@ -240,7 +254,7 @@ public class ClipAnimationHelper { return mCurrentRectWithInsets; } - private void applySurfaceParams(@Nullable SyncRtSurfaceTransactionApplierCompat + public static void applySurfaceParams(@Nullable SyncRtSurfaceTransactionApplierCompat syncTransactionApplier, SurfaceParams[] params) { if (syncTransactionApplier != null) { syncTransactionApplier.scheduleApply(params); @@ -375,12 +389,14 @@ public class ClipAnimationHelper { float progress; public float offsetX; public float offsetScale; - @Nullable RectF currentRect; + public @Nullable RectF currentRect; float targetAlpha; boolean forLiveTile; float cornerRadius; + boolean launcherOnTop; - SyncRtSurfaceTransactionApplierCompat syncTransactionApplier; + public RemoteAnimationTargetSet targetSet; + public SyncRtSurfaceTransactionApplierCompat syncTransactionApplier; public TransformParams() { progress = 0; @@ -390,6 +406,7 @@ public class ClipAnimationHelper { targetAlpha = 0; forLiveTile = false; cornerRadius = -1; + launcherOnTop = false; } public TransformParams setProgress(float progress) { @@ -424,6 +441,16 @@ public class ClipAnimationHelper { return this; } + public TransformParams setLauncherOnTop(boolean launcherOnTop) { + this.launcherOnTop = launcherOnTop; + return this; + } + + public TransformParams setTargetSet(RemoteAnimationTargetSet targetSet) { + this.targetSet = targetSet; + return this; + } + public TransformParams setSyncTransactionApplier( SyncRtSurfaceTransactionApplierCompat applier) { this.syncTransactionApplier = applier; 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 71ad8ba8be..41017cae01 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 @@ -25,6 +25,7 @@ import androidx.annotation.UiThread; import com.android.launcher3.Utilities; import com.android.launcher3.util.Preconditions; +import com.android.quickstep.TouchInteractionService; import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; @@ -40,12 +41,6 @@ import java.util.function.Consumer; */ public class RecentsAnimationListenerSet implements RecentsAnimationListener { - // The actual app surface is replaced by a screenshot upon recents animation cancelation when - // 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; - private final Set mListeners = new ArraySet<>(); private final boolean mShouldMinimizeSplitScreen; private final Consumer mOnFinishListener; @@ -57,6 +52,8 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { Consumer onFinishListener) { mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen; mOnFinishListener = onFinishListener; + TouchInteractionService.getSwipeSharedState().setRecentsAnimationCanceledCallback( + () -> mController.cleanupScreenshot()); } @UiThread @@ -108,14 +105,9 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { public final void onAnimationCanceled(ThumbnailData thumbnailData) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { for (SwipeAnimationListener listener : getListeners()) { - listener.onRecentsAnimationCanceled(); + listener.onRecentsAnimationCanceled(thumbnailData); } }); - // TODO: handle the transition better instead of simply using a transition delay. - if (thumbnailData != null) { - MAIN_EXECUTOR.getHandler().postDelayed(() -> mController.cleanupScreenshot(), - TRANSITION_DELAY); - } } private SwipeAnimationListener[] getListeners() { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java index 3da6b78e72..5ab335a484 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java @@ -114,6 +114,10 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet { void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet); - void onRecentsAnimationCanceled(); + /** + * Callback from the system when the recents animation is canceled. {@param thumbnailData} + * is passed back for rendering screenshot to replace live tile. + */ + void onRecentsAnimationCanceled(ThumbnailData thumbnailData); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 4c308fb8c0..8651095f30 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -174,12 +174,11 @@ public class LauncherRecentsView extends RecentsView implements StateL @Override protected void onTaskLaunchAnimationUpdate(float progress, TaskView tv) { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - if (mRecentsAnimationWrapper.targetSet != null && tv.isRunningTask()) { + if (tv.isRunningTask()) { mTransformParams.setProgress(1 - progress) .setSyncTransactionApplier(mSyncTransactionApplier) .setForLiveTile(true); - mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, - mTransformParams); + mClipAnimationHelper.applyTransform(mTransformParams); } else { redrawLiveTile(true); } @@ -212,9 +211,18 @@ public class LauncherRecentsView extends RecentsView implements StateL @Override public void redrawLiveTile(boolean mightNeedToRefill) { + ClipAnimationHelper.TransformParams transformParams = getLiveTileParams(mightNeedToRefill); + if (transformParams != null) { + mClipAnimationHelper.applyTransform(transformParams); + } + } + + @Override + public ClipAnimationHelper.TransformParams getLiveTileParams( + boolean mightNeedToRefill) { if (!mEnableDrawingLiveTile || mRecentsAnimationWrapper == null || mClipAnimationHelper == null) { - return; + return null; } TaskView taskView = getRunningTaskView(); if (taskView != null) { @@ -236,12 +244,11 @@ public class LauncherRecentsView extends RecentsView implements StateL mTempRectF.set(mTempRect); mTransformParams.setProgress(1f) .setCurrentRectAndTargetAlpha(mTempRectF, taskView.getAlpha()) - .setSyncTransactionApplier(mSyncTransactionApplier); - if (mRecentsAnimationWrapper.targetSet != null) { - mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, - mTransformParams); - } + .setSyncTransactionApplier(mSyncTransactionApplier) + .setTargetSet(mRecentsAnimationWrapper.targetSet) + .setLauncherOnTop(true); } + return mTransformParams; } @Override 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 29e93aa8d3..a659bdcef0 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 @@ -869,7 +869,9 @@ public abstract class RecentsView extends PagedView impl setEnableFreeScroll(true); setEnableDrawingLiveTile(true); setOnScrollChangeListener(null); - setRunningTaskViewShowScreenshot(true); + if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { + setRunningTaskViewShowScreenshot(true); + } setRunningTaskHidden(false); animateUpRunningTaskIconScale(); } @@ -1801,10 +1803,19 @@ public abstract class RecentsView extends PagedView impl } } + public ClipAnimationHelper getClipAnimationHelper() { + return mClipAnimationHelper; + } + public ClipAnimationHelper getTempClipAnimationHelper() { return mTempClipAnimationHelper; } + public ClipAnimationHelper.TransformParams getLiveTileParams( + boolean mightNeedToRefill) { + return null; + } + private void updateEnabledOverlays() { int overlayEnabledPage = mOverlayEnabled ? getNextPage() : -1; int taskCount = getTaskViewCount(); diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 2d4b136139..27b94f039b 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -34,6 +34,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.BiPredicate; @@ -97,6 +98,8 @@ public interface ActivityControlHelper { default void closeOverlay() { } + default void switchToScreenshot(ThumbnailData thumbnailData, Runnable runnable) {} + interface AnimationFactory { enum ShelfAnimState { From 43c3d2d40aded198d52dfdac731ef4f3ce1b7223 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 3 Oct 2019 17:09:16 -0700 Subject: [PATCH 081/109] Diagnosing anomalies prior to swiping up to Home Bug: 141864547 Change-Id: I5f3814c6a90df85136484813ca4ee684da101016 --- .../com/android/launcher3/tapl/LauncherInstrumentation.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 2e9cb81f0c..28f57f0ebe 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -543,6 +543,9 @@ public final class LauncherInstrumentation { // accessibility events prior to pressing Home. final String action; if (getNavigationModel() == NavigationModel.ZERO_BUTTON) { + final String anomaly = getAnomalyMessage(); + if (anomaly != null) fail("Can't swipe up to Home: " + anomaly); + final Point displaySize = getRealDisplaySize(); if (hasLauncherObject("deep_shortcuts_container")) { From f1424a3b38bdbd7fde540a1b54b54f279c24a4b7 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Fri, 4 Oct 2019 15:15:19 -0700 Subject: [PATCH 082/109] Decouple grid size and widget preview size in WidgetsRecyclerView Test: Manual Bug:142148773 Change-Id: I59aa29e95ddb7d6002a88cf853bae5fcf9811154 --- src/com/android/launcher3/DeviceProfile.java | 2 ++ src/com/android/launcher3/WidgetPreviewLoader.java | 2 +- src/com/android/launcher3/widget/WidgetCell.java | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index c034d2de29..736142f190 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -111,6 +111,7 @@ public class DeviceProfile { // All apps public int allAppsCellHeightPx; + public int allAppsCellWidthPx; public int allAppsIconSizePx; public int allAppsIconDrawablePaddingPx; public float allAppsIconTextSizePx; @@ -349,6 +350,7 @@ public class DeviceProfile { allAppsIconDrawablePaddingPx = iconDrawablePaddingPx; allAppsCellHeightPx = getCellSize().y; } + allAppsCellWidthPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx; if (isVerticalBarLayout()) { // Always hide the Workspace text with vertical bar layout. diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 003bcc1ce2..c6381b058c 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -450,7 +450,7 @@ public class WidgetPreviewLoader { private Bitmap generateShortcutPreview(BaseActivity launcher, ShortcutConfigActivityInfo info, int maxWidth, int maxHeight, Bitmap preview) { - int iconSize = launcher.getDeviceProfile().iconSizePx; + int iconSize = launcher.getDeviceProfile().allAppsIconSizePx; int padding = launcher.getResources() .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding); diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index dc4af8caf9..412fb7ba6b 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -103,7 +103,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { private void setContainerWidth() { DeviceProfile profile = mActivity.getDeviceProfile(); - mCellSize = (int) (profile.cellWidthPx * WIDTH_SCALE); + mCellSize = (int) (profile.allAppsCellWidthPx * WIDTH_SCALE); mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE); } From aa038af6b3da0633c229f053c3f272bb452e4632 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Fri, 4 Oct 2019 16:37:12 -0700 Subject: [PATCH 083/109] Scale Icon badges for shortcut and widgets Test: Manual Bug: 141262820 Change-Id: I03edc986e3fe1876b6b7ed179b96864d587cb137 --- .../com/android/launcher3/icons/BaseIconFactory.java | 12 +++++++++++- src/com/android/launcher3/Utilities.java | 2 +- .../android/launcher3/graphics/DrawableFactory.java | 7 +++---- src/com/android/launcher3/widget/WidgetCell.java | 12 ++++++++---- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java index fc7d6b329f..f491ed73f4 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Process; import android.os.UserHandle; + import androidx.annotation.NonNull; /** @@ -35,6 +36,8 @@ public class BaseIconFactory implements AutoCloseable { static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; + private static final float ICON_BADGE_SCALE = 0.444f; + private final Rect mOldBounds = new Rect(); protected final Context mContext; private final Canvas mCanvas; @@ -254,7 +257,7 @@ public class BaseIconFactory implements AutoCloseable { * Adds the {@param badge} on top of {@param target} using the badge dimensions. */ public void badgeWithDrawable(Canvas target, Drawable badge) { - int badgeSize = mContext.getResources().getDimensionPixelSize(R.dimen.profile_badge_size); + int badgeSize = getBadgeSizeForIconSize(mIconBitmapSize); badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize, mIconBitmapSize, mIconBitmapSize); badge.draw(target); @@ -334,6 +337,13 @@ public class BaseIconFactory implements AutoCloseable { iconDpi); } + /** + * Returns the correct badge size given an icon size + */ + public static int getBadgeSizeForIconSize(int iconSize) { + return (int) (ICON_BADGE_SCALE * iconSize); + } + /** * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size. * This allows the badging to be done based on the action bitmap size rather than diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 6ddebe75d0..c5f26aaf1b 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -584,7 +584,7 @@ public final class Utilities { LauncherIcons li = LauncherIcons.obtain(appState.getContext()); Bitmap badge = li.getShortcutInfoBadge(si, appState.getIconCache()).iconBitmap; li.recycle(); - float badgeSize = launcher.getResources().getDimension(R.dimen.profile_badge_size); + float badgeSize = iconSize * LauncherIcons.getBadgeSizeForIconSize(iconSize); float insetFraction = (iconSize - badgeSize) / iconSize; return new InsetDrawable(new FastBitmapDrawable(badge), insetFraction, insetFraction, 0, 0); diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java index 288749fa7e..837301fb89 100644 --- a/src/com/android/launcher3/graphics/DrawableFactory.java +++ b/src/com/android/launcher3/graphics/DrawableFactory.java @@ -80,26 +80,25 @@ public class DrawableFactory implements ResourceBasedOverride { * Returns a drawable that can be used as a badge for the user or null. */ @UiThread - public Drawable getBadgeForUser(UserHandle user, Context context) { + public Drawable getBadgeForUser(UserHandle user, Context context, int badgeSize) { if (mMyUser.equals(user)) { return null; } - Bitmap badgeBitmap = getUserBadge(user, context); + Bitmap badgeBitmap = getUserBadge(user, context, badgeSize); FastBitmapDrawable d = new FastBitmapDrawable(badgeBitmap); d.setFilterBitmap(true); d.setBounds(0, 0, badgeBitmap.getWidth(), badgeBitmap.getHeight()); return d; } - protected synchronized Bitmap getUserBadge(UserHandle user, Context context) { + protected synchronized Bitmap getUserBadge(UserHandle user, Context context, int badgeSize) { Bitmap badgeBitmap = mUserBadges.get(user); if (badgeBitmap != null) { return badgeBitmap; } final Resources res = context.getApplicationContext().getResources(); - int badgeSize = res.getDimensionPixelSize(R.dimen.profile_badge_size); badgeBitmap = Bitmap.createBitmap(badgeSize, badgeSize, Bitmap.Config.ARGB_8888); Drawable drawable = context.getPackageManager().getUserBadgedDrawableForDensity( diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index 412fb7ba6b..6944879beb 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -37,6 +37,7 @@ import com.android.launcher3.SimpleOnStylusPressListener; import com.android.launcher3.StylusEventHelper; import com.android.launcher3.WidgetPreviewLoader; import com.android.launcher3.graphics.DrawableFactory; +import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.model.WidgetItem; /** @@ -80,6 +81,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { private Bitmap mDeferredBitmap; protected final BaseActivity mActivity; + protected DeviceProfile mDeviceProfile; public WidgetCell(Context context) { this(context, null); @@ -93,6 +95,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { super(context, attrs, defStyle); mActivity = BaseActivity.fromContext(context); + mDeviceProfile = mActivity.getDeviceProfile(); mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this); setContainerWidth(); @@ -102,8 +105,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { } private void setContainerWidth() { - DeviceProfile profile = mActivity.getDeviceProfile(); - mCellSize = (int) (profile.allAppsCellWidthPx * WIDTH_SCALE); + mCellSize = (int) (mDeviceProfile.allAppsCellWidthPx * WIDTH_SCALE); mPresetPreviewSize = (int) (mCellSize * PREVIEW_SCALE); } @@ -180,8 +182,10 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { return; } if (bitmap != null) { - mWidgetImage.setBitmap(bitmap, DrawableFactory.INSTANCE.get(getContext()) - .getBadgeForUser(mItem.user, getContext())); + mWidgetImage.setBitmap(bitmap, + DrawableFactory.INSTANCE.get(getContext()).getBadgeForUser(mItem.user, + getContext(), BaseIconFactory.getBadgeSizeForIconSize( + mDeviceProfile.allAppsIconSizePx))); if (mAnimatePreview) { mWidgetImage.setAlpha(0f); ViewPropertyAnimator anim = mWidgetImage.animate(); From d230af4e096882c23b217fa842042a00d8b5c333 Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 4 Oct 2019 17:12:26 -0700 Subject: [PATCH 084/109] Increasing wait time for navigation mode switch. Sometimes this fails in Cuttlefish. Change-Id: Ifa2ffed5165625d51441fc3b203185fc55f7d53f --- .../src/com/android/quickstep/NavigationModeSwitchRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java index e29552713d..c2197ab709 100644 --- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java +++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java @@ -181,7 +181,7 @@ public class NavigationModeSwitchRule implements TestRule { SysUINavigationMode.INSTANCE.get(targetContext); targetContext.getMainExecutor().execute(() -> sysUINavigationMode.addModeChangeListener(listener)); - latch.await(10, TimeUnit.SECONDS); + latch.await(60, TimeUnit.SECONDS); targetContext.getMainExecutor().execute(() -> sysUINavigationMode.removeModeChangeListener(listener)); assertTrue("Navigation mode didn't change to " + expectedMode, From af33f2c9d4063c2ad95a92777cbd5e66d81d3fab Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 4 Oct 2019 12:55:22 -0700 Subject: [PATCH 085/109] Fix quickswitch flickers/ignored swipes - Don't set current page to running task when applying load plan, if we are already settling on a new task to launch. - When starting a new task, finish to the running app if that's the task being started (should not happen with above change) - When disabling free scroll mode, don't snap to a page if we're already on it. This was setting mNextPage so the first check was falsing. Bug: 142068081 Change-Id: I5b392d9726a81c51718d2f94eee6cd4f78b61f69 --- .../quickstep/WindowTransformSwipeHandler.java | 10 +++++++++- .../com/android/quickstep/views/RecentsView.java | 14 ++++++++------ src/com/android/launcher3/PagedView.java | 4 +++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 411a8088c7..c80dede537 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -922,7 +922,15 @@ public class WindowTransformSwipeHandler windowAnim.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { - setStateOnUiThread(target.endState); + if (target == NEW_TASK && mRecentsView != null + && mRecentsView.getNextPage() == mRecentsView.getRunningTaskIndex()) { + // We are about to launch the current running task, so use LAST_TASK state + // instead of NEW_TASK. This could happen, for example, if our scroll is + // aborted after we determined the target to be NEW_TASK. + setStateOnUiThread(LAST_TASK.endState); + } else { + setStateOnUiThread(target.endState); + } } }); windowAnim.start(); 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 554f4372c3..02c43e4ad0 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 @@ -17,7 +17,6 @@ package com.android.quickstep.views; import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_PIXELS; - import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; @@ -573,11 +572,14 @@ public abstract class RecentsView extends PagedView impl taskView.bind(task); } - TaskView runningTaskView = getRunningTaskView(); - if (runningTaskView != null) { - setCurrentPage(indexOfChild(runningTaskView)); - } else if (getTaskViewCount() > 0) { - setCurrentPage(indexOfChild(getTaskViewAt(0))); + if (mNextPage == INVALID_PAGE) { + // Set the current page to the running task, but not if settling on new task. + TaskView runningTaskView = getRunningTaskView(); + if (runningTaskView != null) { + setCurrentPage(indexOfChild(runningTaskView)); + } else if (getTaskViewCount() > 0) { + setCurrentPage(indexOfChild(getTaskViewAt(0))); + } } if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreResetTaskView) { diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 5c790f3797..ff2b400387 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1088,7 +1088,9 @@ public abstract class PagedView extends ViewGrou if (mFreeScroll) { setCurrentPage(getNextPage()); } else if (wasFreeScroll) { - snapToPage(getNextPage()); + if (getScrollForPage(getNextPage()) != getScrollX()) { + snapToPage(getNextPage()); + } } } From 1b92f6d964fe86ed56334dfdef7aa30f862bfeab Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 4 Oct 2019 11:00:01 -0700 Subject: [PATCH 086/109] Reduce risk of flakes in memory leak detection tests. Now performing jreck@-style garbage collection prior to getting Launcher PSS. The reduces PSS noise from ~700KB to ~250KB (std dev). The tests (MemoryTests) run outside of Launcher process and communicate with Launcher via RPC. The change is in the RPC handler that lives in Launcher and returns Launcher PSS to the test. Bug: 139137636 Change-Id: I457e590b005dac53345f4223d972c7961754938c --- .../testing/TestInformationHandler.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 619293bd84..7931c96493 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -36,7 +36,9 @@ import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.util.ResourceBasedOverride; import java.util.LinkedList; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; public class TestInformationHandler implements ResourceBasedOverride { @@ -137,6 +139,7 @@ public class TestInformationHandler implements ResourceBasedOverride { } case TestProtocol.REQUEST_TOTAL_PSS_KB: { + runGcAndFinalizersSync(); Debug.MemoryInfo mem = new Debug.MemoryInfo(); Debug.getMemoryInfo(mem); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss()); @@ -173,4 +176,29 @@ public class TestInformationHandler implements ResourceBasedOverride { final LauncherModel model = LauncherAppState.getInstance(mContext).getModel(); return model.getCallback() == null || model.isModelLoaded(); } + + private static void runGcAndFinalizersSync() { + Runtime.getRuntime().gc(); + Runtime.getRuntime().runFinalization(); + + final CountDownLatch fence = new CountDownLatch(1); + new Object() { + @Override + protected void finalize() throws Throwable { + try { + fence.countDown(); + } finally { + super.finalize(); + } + } + }; + try { + do { + Runtime.getRuntime().gc(); + Runtime.getRuntime().runFinalization(); + } while (!fence.await(100, TimeUnit.MILLISECONDS)); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + } } From 92a015f2fcbbb0fd48225be02bcaab7495c27165 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 30 Sep 2019 15:56:39 -0700 Subject: [PATCH 087/109] 1/ Renaming some classes for clarity - SwipeAnimationTargetSet -> RecentsAnimationTargets - RemoteAnimationTargetSet -> RemoteAnimationTargets - RecentsAnimationListenerSet -> RecentsAnimationCallbacks - SwipeAnimationTargetSet.SwipeAnimationListener -> RecentsAnimationCallbacks.RecentsAnimationListener - ClipAnimationHelper -> AppWindowAnimationHelper - AssistantTouchConsumer -> AssistantInputConsumer Bug: 141886704 Change-Id: I78485a1651bb360ffbac2d0c462855931a995ee1 --- .../AppToOverviewAnimationProvider.java | 6 +-- .../FallbackActivityControllerHelper.java | 4 +- .../LauncherAppTransitionManagerImpl.java | 4 +- .../states/BackgroundAppState.java | 2 +- .../AppToOverviewAnimationProvider.java | 12 +++--- .../android/quickstep/BaseSwipeUpHandler.java | 42 +++++++++---------- .../FallbackActivityControllerHelper.java | 4 +- .../android/quickstep/RecentsActivity.java | 4 +- .../quickstep/RecentsAnimationWrapper.java | 10 ++--- .../android/quickstep/SwipeSharedState.java | 27 ++++++------ .../com/android/quickstep/TaskViewUtils.java | 29 ++++++------- .../quickstep/TouchInteractionService.java | 6 +-- .../WindowTransformSwipeHandler.java | 18 ++++---- .../fallback/FallbackRecentsView.java | 2 +- ...sumer.java => AssistantInputConsumer.java} | 6 +-- .../DeviceLockedInputConsumer.java | 34 ++++++++------- .../FallbackNoButtonInputConsumer.java | 10 ++--- .../OtherActivityInputConsumer.java | 8 ++-- ...per.java => AppWindowAnimationHelper.java} | 12 +++--- ...et.java => RecentsAnimationCallbacks.java} | 42 ++++++++++++------- ...tSet.java => RecentsAnimationTargets.java} | 25 ++++------- .../quickstep/views/LauncherRecentsView.java | 16 +++---- .../android/quickstep/views/RecentsView.java | 36 ++++++++-------- .../QuickstepAppTransitionManagerImpl.java | 4 +- .../quickstep/ActivityControlHelper.java | 4 +- ...etSet.java => RemoteAnimationTargets.java} | 4 +- .../util/RemoteFadeOutAnimationListener.java | 4 +- 27 files changed, 190 insertions(+), 185 deletions(-) rename quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/{AssistantTouchConsumer.java => AssistantInputConsumer.java} (98%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/util/{ClipAnimationHelper.java => AppWindowAnimationHelper.java} (98%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/util/{RecentsAnimationListenerSet.java => RecentsAnimationCallbacks.java} (69%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/util/{SwipeAnimationTargetSet.java => RecentsAnimationTargets.java} (82%) rename quickstep/src/com/android/quickstep/util/{RemoteAnimationTargetSet.java => RemoteAnimationTargets.java} (96%) diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java index ddf0fff523..b1a388133c 100644 --- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -32,7 +32,7 @@ import android.util.Log; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAnimationRunner; import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.IconRecentsView; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; @@ -113,8 +113,8 @@ final class AppToOverviewAnimationProvider imple return anim; } - RemoteAnimationTargetSet targetSet = - new RemoteAnimationTargetSet(appTargets, wallpaperTargets, MODE_CLOSING); + RemoteAnimationTargets targetSet = + new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING); mRecentsView.setTransitionedFromApp(!targetSet.isAnimatingHome()); RemoteAnimationTargetCompat recentsTarget = null; diff --git a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java index 49945263a4..37c2c04306 100644 --- a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java +++ b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java @@ -27,7 +27,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.IconRecentsView; import java.util.function.BiPredicate; @@ -59,7 +59,7 @@ public final class FallbackActivityControllerHelper extends boolean isAnimatingToRecents = false; @Override - public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { + public void onRemoteAnimationReceived(RemoteAnimationTargets targets) { isAnimatingToRecents = targets != null && targets.isAnimatingHome(); if (!isAnimatingToRecents) { rv.setAlpha(1); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 33843977e6..d84248419e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -36,7 +36,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.SpringAnimationBuilder; -import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -71,7 +71,7 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets); - ClipAnimationHelper helper = new ClipAnimationHelper(mLauncher); + AppWindowAnimationHelper helper = new AppWindowAnimationHelper(mLauncher); anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION)); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 468b8afc97..e4e60a04b1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -78,7 +78,7 @@ public class BackgroundAppState extends OverviewState { } else { dummyTask = recentsView.getTaskViewAt(0); } - return recentsView.getTempClipAnimationHelper().updateForFullscreenOverview(dummyTask) + return recentsView.getTempAppWindowAnimationHelper().updateForFullscreenOverview(dummyTask) .getScaleAndTranslation(); } 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 89c34d34a8..1b49732cb2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -30,9 +30,9 @@ import android.view.View; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; @@ -115,7 +115,7 @@ final class AppToOverviewAnimationProvider imple return anim; } - RemoteAnimationTargetSet targetSet = new RemoteAnimationTargetSet(appTargets, + RemoteAnimationTargets targetSet = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING); // Use the top closing app to determine the insets for the animation @@ -126,7 +126,7 @@ final class AppToOverviewAnimationProvider imple return anim; } - final ClipAnimationHelper clipHelper = new ClipAnimationHelper(mActivity); + final AppWindowAnimationHelper clipHelper = new AppWindowAnimationHelper(mActivity); // At this point, the activity is already started and laid-out. Get the home-bounds // relative to the screen using the rootView of the activity. @@ -142,7 +142,7 @@ final class AppToOverviewAnimationProvider imple clipHelper.updateTargetRect(targetRect); clipHelper.prepareAnimation(mActivity.getDeviceProfile(), false /* isOpening */); - ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams() + AppWindowAnimationHelper.TransformParams params = new AppWindowAnimationHelper.TransformParams() .setSyncTransactionApplier(new SyncRtSurfaceTransactionApplierCompat(rootView)); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(RECENTS_LAUNCH_DURATION); @@ -156,7 +156,7 @@ final class AppToOverviewAnimationProvider imple if (targetSet.isAnimatingHome()) { // If we are animating home, fade in the opening targets - RemoteAnimationTargetSet openingSet = new RemoteAnimationTargetSet(appTargets, + RemoteAnimationTargets openingSet = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING); TransactionCompat transaction = new TransactionCompat(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index ed6a7e8499..770857ba43 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -61,12 +61,12 @@ import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.ClipAnimationHelper; -import com.android.quickstep.util.ClipAnimationHelper.TransformParams; +import com.android.quickstep.util.AppWindowAnimationHelper; +import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.RemoteAnimationTargetSet; -import com.android.quickstep.util.SwipeAnimationTargetSet; -import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; +import com.android.quickstep.util.RemoteAnimationTargets; +import com.android.quickstep.util.RecentsAnimationTargets; +import com.android.quickstep.util.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.InputConsumerController; @@ -80,7 +80,7 @@ import java.util.function.Consumer; */ @TargetApi(Build.VERSION_CODES.Q) public abstract class BaseSwipeUpHandler - implements SwipeAnimationListener { + implements RecentsAnimationListener { private static final String TAG = "BaseSwipeUpHandler"; protected static final Rect TEMP_RECT = new Rect(); @@ -102,7 +102,7 @@ public abstract class BaseSwipeUpHandler resultCallback) { @@ -257,7 +257,7 @@ public abstract class BaseSwipeUpHandler mCallbacks = new ArrayList<>(); - public SwipeAnimationTargetSet targetSet; + public RecentsAnimationTargets targetSet; private boolean mWindowThresholdCrossed = false; @@ -69,7 +69,7 @@ public class RecentsAnimationWrapper { } @UiThread - public synchronized void setController(SwipeAnimationTargetSet targetSet) { + public synchronized void setController(RecentsAnimationTargets targetSet) { Preconditions.assertUIThread(); this.targetSet = targetSet; @@ -127,7 +127,7 @@ public class RecentsAnimationWrapper { private void finishAndClear(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint) { - SwipeAnimationTargetSet controller = targetSet; + RecentsAnimationTargets controller = targetSet; targetSet = null; disableInputProxy(); if (controller != null) { @@ -221,7 +221,7 @@ public class RecentsAnimationWrapper { } } - public SwipeAnimationTargetSet getController() { + public RecentsAnimationTargets getController() { return targetSet; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java index 8301f363b6..6b98a89abc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java @@ -22,9 +22,10 @@ import android.util.Log; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.Preconditions; -import com.android.quickstep.util.RecentsAnimationListenerSet; -import com.android.quickstep.util.SwipeAnimationTargetSet; -import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; +import com.android.quickstep.util.RecentsAnimationCallbacks; +import com.android.quickstep.util.RecentsAnimationTargets; +import com.android.quickstep.util.RecentsAnimationCallbacks.RecentsAnimationListener; + import com.android.systemui.shared.recents.model.ThumbnailData; import java.io.PrintWriter; @@ -32,12 +33,14 @@ import java.io.PrintWriter; /** * Utility class used to store state information shared across multiple transitions. */ -public class SwipeSharedState implements SwipeAnimationListener { +public class SwipeSharedState implements RecentsAnimationListener { private OverviewComponentObserver mOverviewComponentObserver; - private RecentsAnimationListenerSet mRecentsAnimationListener; - private SwipeAnimationTargetSet mLastAnimationTarget; + private RecentsAnimationCallbacks mRecentsAnimationListener; + private RecentsAnimationTargets mLastAnimationTarget; + + // TODO: Remove private Runnable mRecentsAnimationCanceledCallback; private boolean mLastAnimationCancelled = false; @@ -54,7 +57,7 @@ public class SwipeSharedState implements SwipeAnimationListener { } @Override - public final void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) { + public final void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { mLastAnimationTarget = targetSet; mLastAnimationCancelled = false; @@ -113,13 +116,13 @@ public class SwipeSharedState implements SwipeAnimationListener { mLastAnimationRunning = false; } - private void onSwipeAnimationFinished(SwipeAnimationTargetSet targetSet) { + private void onSwipeAnimationFinished(RecentsAnimationTargets targetSet) { if (mLastAnimationTarget == targetSet) { mLastAnimationRunning = false; } } - public RecentsAnimationListenerSet newRecentsAnimationListenerSet() { + public RecentsAnimationCallbacks newRecentsAnimationListenerSet() { Preconditions.assertUIThread(); if (mLastAnimationRunning) { @@ -134,17 +137,17 @@ public class SwipeSharedState implements SwipeAnimationListener { clearListenerState(false /* finishAnimation */); boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false : mOverviewComponentObserver.getActivityControlHelper().shouldMinimizeSplitScreen(); - mRecentsAnimationListener = new RecentsAnimationListenerSet( + mRecentsAnimationListener = new RecentsAnimationCallbacks( shouldMinimiseSplitScreen, this::onSwipeAnimationFinished); mRecentsAnimationListener.addListener(this); return mRecentsAnimationListener; } - public RecentsAnimationListenerSet getActiveListener() { + public RecentsAnimationCallbacks getActiveListener() { return mRecentsAnimationListener; } - public void applyActiveRecentsAnimationState(SwipeAnimationListener listener) { + public void applyActiveRecentsAnimationState(RecentsAnimationListener listener) { if (mLastAnimationTarget != null) { listener.onRecentsAnimationStart(mLastAnimationTarget); } else if (mLastAnimationCancelled) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java index b4a7996fb7..b55fd8b54d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java @@ -31,9 +31,9 @@ import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.ItemInfo; import com.android.launcher3.Utilities; -import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.MultiValueUpdateListener; -import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; @@ -118,16 +118,17 @@ public final class TaskViewUtils { */ public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges, RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, final ClipAnimationHelper inOutHelper) { + RemoteAnimationTargetCompat[] wallpaperTargets, final AppWindowAnimationHelper inOutHelper) { SyncRtSurfaceTransactionApplierCompat applier = new SyncRtSurfaceTransactionApplierCompat(v); - final RemoteAnimationTargetSet targetSet = - new RemoteAnimationTargetSet(appTargets, wallpaperTargets, MODE_OPENING); + final RemoteAnimationTargets targetSet = + new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING); targetSet.addDependentTransactionApplier(applier); - ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams() - .setSyncTransactionApplier(applier) - .setTargetSet(targetSet) - .setLauncherOnTop(true); + AppWindowAnimationHelper.TransformParams params = + new AppWindowAnimationHelper.TransformParams() + .setSyncTransactionApplier(applier) + .setTargetSet(targetSet) + .setLauncherOnTop(true); final RecentsView recentsView = v.getRecentsView(); final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); @@ -165,19 +166,19 @@ public final class TaskViewUtils { // Append the surface transform params for the app that's being opened. Collections.addAll(surfaceParamsList, inOutHelper.getSurfaceParams(params)); - ClipAnimationHelper liveTileClipAnimationHelper = + AppWindowAnimationHelper liveTileAnimationHelper = v.getRecentsView().getClipAnimationHelper(); - if (liveTileClipAnimationHelper != null) { + if (liveTileAnimationHelper != null) { // Append the surface transform params for the live tile app. - ClipAnimationHelper.TransformParams liveTileParams = + AppWindowAnimationHelper.TransformParams liveTileParams = v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */); if (liveTileParams != null) { Collections.addAll(surfaceParamsList, - liveTileClipAnimationHelper.getSurfaceParams(liveTileParams)); + liveTileAnimationHelper.getSurfaceParams(liveTileParams)); } } // Apply surface transform using the surface params list. - ClipAnimationHelper.applySurfaceParams(params.syncTransactionApplier, + AppWindowAnimationHelper.applySurfaceParams(params.syncTransactionApplier, surfaceParamsList.toArray(new SurfaceParams[surfaceParamsList.size()])); // Get the task bounds for the app that's being opened after surface transform // update. diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 7c1bc4ed8a..3b48fa7014 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -84,7 +84,7 @@ import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; -import com.android.quickstep.inputconsumers.AssistantTouchConsumer; +import com.android.quickstep.inputconsumers.AssistantInputConsumer; import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; import com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer; import com.android.quickstep.inputconsumers.InputConsumer; @@ -563,7 +563,7 @@ public class TouchInteractionService extends Service implements // not interrupt it. QuickSwitch assumes that interruption can only happen if the // next gesture is also quick switch. mUncheckedConsumer = - new AssistantTouchConsumer(this, mISystemUiProxy, + new AssistantInputConsumer(this, mISystemUiProxy, mOverviewComponentObserver.getActivityControlHelper(), InputConsumer.NO_OP, mInputMonitorCompat); } else { @@ -613,7 +613,7 @@ public class TouchInteractionService extends Service implements final ActivityControlHelper activityControl = mOverviewComponentObserver.getActivityControlHelper(); if (canTriggerAssistantAction(event)) { - base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base, + base = new AssistantInputConsumer(this, mISystemUiProxy, activityControl, base, mInputMonitorCompat); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 5c90d71c6f..fd1ed626e0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -79,9 +79,9 @@ import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; -import com.android.quickstep.util.ClipAnimationHelper.TargetAlphaProvider; +import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.SwipeAnimationTargetSet; +import com.android.quickstep.util.RecentsAnimationTargets; import com.android.quickstep.views.LiveTileOverlay; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -547,7 +547,7 @@ public class WindowTransformSwipeHandler @Override public void updateFinalShift() { - SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController(); + RecentsAnimationTargets controller = mRecentsAnimationWrapper.getController(); if (controller != null) { applyTransformUnchecked(); updateSysUiFlags(mCurrentShift.value); @@ -555,8 +555,8 @@ public class WindowTransformSwipeHandler if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (mRecentsAnimationWrapper.getController() != null) { - mLiveTileOverlay.update(mClipAnimationHelper.getCurrentRectWithInsets(), - mClipAnimationHelper.getCurrentCornerRadius()); + mLiveTileOverlay.update(mAppWindowAnimationHelper.getCurrentRectWithInsets(), + mAppWindowAnimationHelper.getCurrentCornerRadius()); } } @@ -605,7 +605,7 @@ public class WindowTransformSwipeHandler } @Override - public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) { + public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { super.onRecentsAnimationStart(targetSet); TOUCH_INTERACTION_LOG.addLog("startRecentsAnimationCallback", targetSet.apps.length); setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); @@ -886,7 +886,7 @@ public class WindowTransformSwipeHandler @NonNull @Override public RectF getWindowTargetRect() { - RectF fallbackTarget = new RectF(mClipAnimationHelper.getTargetRect()); + RectF fallbackTarget = new RectF(mAppWindowAnimationHelper.getTargetRect()); Utilities.scaleRectFAboutCenter(fallbackTarget, 0.25f); return fallbackTarget; } @@ -1108,7 +1108,7 @@ public class WindowTransformSwipeHandler } private void switchToScreenshot() { - SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController(); + RecentsAnimationTargets controller = mRecentsAnimationWrapper.getController(); if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (controller != null) { // Update the screenshot of the task @@ -1191,7 +1191,7 @@ public class WindowTransformSwipeHandler } private void setTargetAlphaProvider(TargetAlphaProvider provider) { - mClipAnimationHelper.setTaskAlphaCallback(provider); + mAppWindowAnimationHelper.setTaskAlphaCallback(provider); updateFinalShift(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java index 7f1aae5e22..79e71a1f94 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -142,7 +142,7 @@ public class FallbackRecentsView extends RecentsView { mZoomTranslationY = 0f; } else { TaskView dummyTask = getTaskViewAt(0); - ScaleAndTranslation sat = getTempClipAnimationHelper() + ScaleAndTranslation sat = getTempAppWindowAnimationHelper() .updateForFullscreenOverview(dummyTask) .getScaleAndTranslation(); mZoomScale = sat.scale; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java similarity index 98% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java rename to quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java index 346969e592..a2a1c43023 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java @@ -57,9 +57,9 @@ import com.android.systemui.shared.system.InputMonitorCompat; /** * Touch consumer for handling events to launch assistant from launcher */ -public class AssistantTouchConsumer extends DelegateInputConsumer { +public class AssistantInputConsumer extends DelegateInputConsumer { - private static final String TAG = "AssistantTouchConsumer"; + private static final String TAG = "AssistantInputConsumer"; private static final long RETRACT_ANIMATION_DURATION_MS = 300; // From //java/com/google/android/apps/gsa/search/shared/util/OpaContract.java. @@ -92,7 +92,7 @@ public class AssistantTouchConsumer extends DelegateInputConsumer { private final Context mContext; private final GestureDetector mGestureDetector; - public AssistantTouchConsumer(Context context, ISystemUiProxy systemUiProxy, + public AssistantInputConsumer(Context context, ISystemUiProxy systemUiProxy, ActivityControlHelper activityControlHelper, InputConsumer delegate, InputMonitorCompat inputMonitor) { super(delegate, inputMonitor); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index d11afaf080..536470bb01 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -43,9 +43,10 @@ import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.SwipeSharedState; -import com.android.quickstep.util.ClipAnimationHelper; -import com.android.quickstep.util.RecentsAnimationListenerSet; -import com.android.quickstep.util.SwipeAnimationTargetSet; +import com.android.quickstep.util.AppWindowAnimationHelper; +import com.android.quickstep.util.RecentsAnimationCallbacks; +import com.android.quickstep.util.RecentsAnimationTargets; + import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -54,7 +55,7 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; * A dummy input consumer used when the device is still locked, e.g. from secure camera. */ public class DeviceLockedInputConsumer implements InputConsumer, - SwipeAnimationTargetSet.SwipeAnimationListener { + RecentsAnimationCallbacks.RecentsAnimationListener { private static final float SCALE_DOWN = 0.75f; @@ -77,9 +78,9 @@ public class DeviceLockedInputConsumer implements InputConsumer, private final InputMonitorCompat mInputMonitorCompat; private final PointF mTouchDown = new PointF(); - private final ClipAnimationHelper mClipAnimationHelper; + private final AppWindowAnimationHelper mAppWindowAnimationHelper; private int mLogId; - private final ClipAnimationHelper.TransformParams mTransformParams; + private final AppWindowAnimationHelper.TransformParams mTransformParams; private final Point mDisplaySize; private final MultiStateCallback mStateCallback; private final RectF mSwipeTouchRegion; @@ -90,7 +91,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, private boolean mThresholdCrossed = false; - private SwipeAnimationTargetSet mTargetSet; + private RecentsAnimationTargets mTargetSet; public DeviceLockedInputConsumer(Context context, SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId, @@ -98,9 +99,9 @@ public class DeviceLockedInputConsumer implements InputConsumer, mContext = context; mTouchSlopSquared = squaredTouchSlop(context); mSwipeSharedState = swipeSharedState; - mClipAnimationHelper = new ClipAnimationHelper(context); + mAppWindowAnimationHelper = new AppWindowAnimationHelper(context); mLogId = logId; - mTransformParams = new ClipAnimationHelper.TransformParams(); + mTransformParams = new AppWindowAnimationHelper.TransformParams(); mInputMonitorCompat = inputMonitorCompat; mSwipeTouchRegion = swipeTouchRegion; mRunningTaskId = runningTaskId; @@ -156,7 +157,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, float dy = Math.max(mTouchDown.y - y, 0); mProgress = dy / mDisplaySize.y; mTransformParams.setProgress(mProgress); - mClipAnimationHelper.applyTransform(mTransformParams); + mAppWindowAnimationHelper.applyTransform(mTransformParams); } break; } @@ -201,7 +202,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, private void startRecentsTransition() { mThresholdCrossed = true; - RecentsAnimationListenerSet newListenerSet = + RecentsAnimationCallbacks newListenerSet = mSwipeSharedState.newRecentsAnimationListenerSet(); newListenerSet.addListener(this); Intent intent = new Intent(Intent.ACTION_MAIN) @@ -215,20 +216,21 @@ public class DeviceLockedInputConsumer implements InputConsumer, } @Override - public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) { + public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { mTargetSet = targetSet; Rect displaySize = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y); RemoteAnimationTargetCompat targetCompat = targetSet.findTask(mRunningTaskId); if (targetCompat != null) { - mClipAnimationHelper.updateSource(displaySize, targetCompat); + mAppWindowAnimationHelper.updateSource(displaySize, targetCompat); } Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN); displaySize.offsetTo(displaySize.left, 0); - mClipAnimationHelper.updateTargetRect(displaySize); - mTransformParams.setTargetSet(mTargetSet).setLauncherOnTop(true); - mClipAnimationHelper.applyTransform(mTransformParams); + mTransformParams.setTargetSet(mTargetSet) + .setLauncherOnTop(true); + mAppWindowAnimationHelper.updateTargetRect(displaySize); + mAppWindowAnimationHelper.applyTransform(mTransformParams); mStateCallback.setState(STATE_TARGET_RECEIVED); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 629d240225..59efb2d05f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -49,7 +49,7 @@ import com.android.quickstep.RecentsModel; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.SwipeAnimationTargetSet; +import com.android.quickstep.util.RecentsAnimationTargets; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -127,9 +127,9 @@ public class FallbackNoButtonInputConsumer extends mSwipeUpOverHome = mRunningOverHome && !mInQuickSwitchMode; if (mSwipeUpOverHome) { - mClipAnimationHelper.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value); + mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value); } else { - mClipAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value); + mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value); } initStateCallbacks(); @@ -414,12 +414,12 @@ public class FallbackNoButtonInputConsumer extends } @Override - public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) { + public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { super.onRecentsAnimationStart(targetSet); mRecentsAnimationWrapper.enableInputConsumer(); if (mRunningOverHome) { - mClipAnimationHelper.prepareAnimation(mDp, true); + mAppWindowAnimationHelper.prepareAnimation(mDp, true); } applyTransformUnchecked(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index f06702dba3..e4d898b952 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -61,7 +61,7 @@ import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; -import com.android.quickstep.util.RecentsAnimationListenerSet; +import com.android.quickstep.util.RecentsAnimationCallbacks; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; @@ -329,7 +329,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC long touchTimeMs, boolean isLikelyToStartNewTask) { TOUCH_INTERACTION_LOG.addLog("startRecentsAnimation"); - RecentsAnimationListenerSet listenerSet = mSwipeSharedState.getActiveListener(); + RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener(); final BaseSwipeUpHandler handler = mHandlerFactory.newHandler(mRunningTask, touchTimeMs, listenerSet != null, isLikelyToStartNewTask); @@ -343,7 +343,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mSwipeSharedState.applyActiveRecentsAnimationState(handler); notifyGestureStarted(); } else { - RecentsAnimationListenerSet newListenerSet = + RecentsAnimationCallbacks newListenerSet = mSwipeSharedState.newRecentsAnimationListenerSet(); newListenerSet.addListener(handler); Intent intent = handler.getLaunchIntent(); @@ -416,7 +416,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } private void removeListener() { - RecentsAnimationListenerSet listenerSet = mSwipeSharedState.getActiveListener(); + RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener(); if (listenerSet != null) { listenerSet.removeListener(mInteractionHandler); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java similarity index 98% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java rename to quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java index 587e9f24a4..dddfc8da34 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java @@ -50,13 +50,11 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat. import com.android.systemui.shared.system.TransactionCompat; import com.android.systemui.shared.system.WindowManagerWrapper; -import java.util.function.BiFunction; - /** * Utility class to handle window clip animation */ @TargetApi(Build.VERSION_CODES.P) -public class ClipAnimationHelper { +public class AppWindowAnimationHelper { // The bounds of the source app in device coordinates private final Rect mSourceStackBounds = new Rect(); @@ -102,7 +100,7 @@ public class ClipAnimationHelper { private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a; private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1; - public ClipAnimationHelper(Context context) { + public AppWindowAnimationHelper(Context context) { mWindowCornerRadius = getWindowCornerRadius(context.getResources()); mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources()); mTaskCornerRadius = TaskCornerRadius.get(context); @@ -319,7 +317,7 @@ public class ClipAnimationHelper { /** * Compute scale and translation y such that the specified task view fills the screen. */ - public ClipAnimationHelper updateForFullscreenOverview(TaskView v) { + public AppWindowAnimationHelper updateForFullscreenOverview(TaskView v) { TaskThumbnailView thumbnailView = v.getThumbnail(); RecentsView recentsView = v.getRecentsView(); fromTaskThumbnailView(thumbnailView, recentsView); @@ -395,7 +393,7 @@ public class ClipAnimationHelper { float cornerRadius; boolean launcherOnTop; - public RemoteAnimationTargetSet targetSet; + public RemoteAnimationTargets targetSet; public SyncRtSurfaceTransactionApplierCompat syncTransactionApplier; public TransformParams() { @@ -446,7 +444,7 @@ public class ClipAnimationHelper { return this; } - public TransformParams setTargetSet(RemoteAnimationTargetSet targetSet) { + public TransformParams setTargetSet(RemoteAnimationTargets targetSet) { this.targetSet = targetSet; return this; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java similarity index 69% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java rename to quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java index 41017cae01..415f7674b8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java @@ -26,30 +26,29 @@ import androidx.annotation.UiThread; import com.android.launcher3.Utilities; import com.android.launcher3.util.Preconditions; import com.android.quickstep.TouchInteractionService; -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; import java.util.Set; import java.util.function.Consumer; /** - * Wrapper around {@link RecentsAnimationListener} which delegates callbacks to multiple listeners + * Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which delegates callbacks to multiple listeners * on the main thread */ -public class RecentsAnimationListenerSet implements RecentsAnimationListener { +public class RecentsAnimationCallbacks implements + com.android.systemui.shared.system.RecentsAnimationListener { - private final Set mListeners = new ArraySet<>(); + private final Set mListeners = new ArraySet<>(); private final boolean mShouldMinimizeSplitScreen; - private final Consumer mOnFinishListener; + private final Consumer mOnFinishListener; private RecentsAnimationControllerCompat mController; private boolean mCancelled; - public RecentsAnimationListenerSet(boolean shouldMinimizeSplitScreen, - Consumer onFinishListener) { + public RecentsAnimationCallbacks(boolean shouldMinimizeSplitScreen, + Consumer onFinishListener) { mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen; mOnFinishListener = onFinishListener; TouchInteractionService.getSwipeSharedState().setRecentsAnimationCanceledCallback( @@ -57,13 +56,13 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { } @UiThread - public void addListener(SwipeAnimationListener listener) { + public void addListener(RecentsAnimationListener listener) { Preconditions.assertUIThread(); mListeners.add(listener); } @UiThread - public void removeListener(SwipeAnimationListener listener) { + public void removeListener(RecentsAnimationListener listener) { Preconditions.assertUIThread(); mListeners.remove(listener); } @@ -75,7 +74,7 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { RemoteAnimationTargetCompat[] wallpaperTargets, Rect homeContentInsets, Rect minimizedHomeBounds) { mController = controller; - SwipeAnimationTargetSet targetSet = new SwipeAnimationTargetSet(controller, appTargets, + RecentsAnimationTargets targetSet = new RecentsAnimationTargets(controller, appTargets, wallpaperTargets, homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen, mOnFinishListener); @@ -83,7 +82,7 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { targetSet.cancelAnimation(); } else { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { - for (SwipeAnimationListener listener : getListeners()) { + for (RecentsAnimationListener listener : getListeners()) { listener.onRecentsAnimationStart(targetSet); } }); @@ -104,18 +103,31 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { @Override public final void onAnimationCanceled(ThumbnailData thumbnailData) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { - for (SwipeAnimationListener listener : getListeners()) { + for (RecentsAnimationListener listener : getListeners()) { listener.onRecentsAnimationCanceled(thumbnailData); } }); } - private SwipeAnimationListener[] getListeners() { - return mListeners.toArray(new SwipeAnimationListener[mListeners.size()]); + private RecentsAnimationListener[] getListeners() { + return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]); } public void cancelListener() { mCancelled = true; onAnimationCanceled(null); } + + /** + * Listener for the recents animation callbacks. + */ + public interface RecentsAnimationListener { + void onRecentsAnimationStart(RecentsAnimationTargets targetSet); + + /** + * Callback from the system when the recents animation is canceled. {@param thumbnailData} + * is passed back for rendering screenshot to replace live tile. + */ + void onRecentsAnimationCanceled(ThumbnailData thumbnailData); + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java similarity index 82% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java rename to quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java index 5ab335a484..187a404b42 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java @@ -28,22 +28,22 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.Consumer; /** - * Extension of {@link RemoteAnimationTargetSet} with additional information about swipe + * Extension of {@link RemoteAnimationTargets} with additional information about swipe * up animation */ -public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet { +public class RecentsAnimationTargets extends RemoteAnimationTargets { private final boolean mShouldMinimizeSplitScreen; - private final Consumer mOnFinishListener; + private final Consumer mOnFinishListener; public final RecentsAnimationControllerCompat controller; public final Rect homeContentInsets; public final Rect minimizedHomeBounds; - public SwipeAnimationTargetSet(RecentsAnimationControllerCompat controller, + public RecentsAnimationTargets(RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets, Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen, - Consumer onFinishListener) { + Consumer onFinishListener) { super(apps, wallpapers, MODE_CLOSING); this.controller = controller; this.homeContentInsets = homeContentInsets; @@ -60,8 +60,8 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet { * Clones the target set without any actual targets. Used only when continuing a gesture after * the actual recents animation has finished. */ - public SwipeAnimationTargetSet cloneWithoutTargets() { - return new SwipeAnimationTargetSet(controller, new RemoteAnimationTargetCompat[0], + public RecentsAnimationTargets cloneWithoutTargets() { + return new RecentsAnimationTargets(controller, new RemoteAnimationTargetCompat[0], new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds, mShouldMinimizeSplitScreen, mOnFinishListener); } @@ -109,15 +109,4 @@ public class SwipeAnimationTargetSet extends RemoteAnimationTargetSet { public void finishAnimation() { finishController(true /* toRecents */, null, false /* sendUserLeaveHint */); } - - public interface SwipeAnimationListener { - - void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet); - - /** - * Callback from the system when the recents animation is canceled. {@param thumbnailData} - * is passed back for rendering screenshot to replace live tile. - */ - void onRecentsAnimationCanceled(ThumbnailData thumbnailData); - } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 8651095f30..0f9184f48d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -48,8 +48,8 @@ import com.android.launcher3.appprediction.PredictionUiStateManager.Client; import com.android.launcher3.uioverrides.DejankBinderTracker; import com.android.launcher3.views.ScrimView; import com.android.quickstep.SysUINavigationMode; -import com.android.quickstep.util.ClipAnimationHelper; -import com.android.quickstep.util.ClipAnimationHelper.TransformParams; +import com.android.quickstep.util.AppWindowAnimationHelper; +import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.LayoutUtils; /** @@ -120,7 +120,7 @@ public class LauncherRecentsView extends RecentsView implements StateL */ @Override public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv, - ClipAnimationHelper helper) { + AppWindowAnimationHelper helper) { AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper); if (!SysUINavigationMode.getMode(mActivity).hasGestures) { @@ -178,7 +178,7 @@ public class LauncherRecentsView extends RecentsView implements StateL mTransformParams.setProgress(1 - progress) .setSyncTransactionApplier(mSyncTransactionApplier) .setForLiveTile(true); - mClipAnimationHelper.applyTransform(mTransformParams); + mAppWindowAnimationHelper.applyTransform(mTransformParams); } else { redrawLiveTile(true); } @@ -211,17 +211,17 @@ public class LauncherRecentsView extends RecentsView implements StateL @Override public void redrawLiveTile(boolean mightNeedToRefill) { - ClipAnimationHelper.TransformParams transformParams = getLiveTileParams(mightNeedToRefill); + AppWindowAnimationHelper.TransformParams transformParams = getLiveTileParams(mightNeedToRefill); if (transformParams != null) { - mClipAnimationHelper.applyTransform(transformParams); + mAppWindowAnimationHelper.applyTransform(transformParams); } } @Override - public ClipAnimationHelper.TransformParams getLiveTileParams( + public AppWindowAnimationHelper.TransformParams getLiveTileParams( boolean mightNeedToRefill) { if (!mEnableDrawingLiveTile || mRecentsAnimationWrapper == null - || mClipAnimationHelper == null) { + || mAppWindowAnimationHelper == null) { return null; } TaskView taskView = getRunningTaskView(); 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 c69bcb621c..cefe2647ee 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 @@ -107,7 +107,7 @@ import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; import com.android.quickstep.ViewUtils; -import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -156,7 +156,7 @@ public abstract class RecentsView extends PagedView impl }; protected RecentsAnimationWrapper mRecentsAnimationWrapper; - protected ClipAnimationHelper mClipAnimationHelper; + protected AppWindowAnimationHelper mAppWindowAnimationHelper; protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier; protected int mTaskWidth; protected int mTaskHeight; @@ -176,7 +176,7 @@ public abstract class RecentsView extends PagedView impl private final ClearAllButton mClearAllButton; private final Rect mClearAllButtonDeadZoneRect = new Rect(); private final Rect mTaskViewDeadZoneRect = new Rect(); - protected final ClipAnimationHelper mTempClipAnimationHelper; + protected final AppWindowAnimationHelper mTempAppWindowAnimationHelper; private final ScrollState mScrollState = new ScrollState(); // Keeps track of the previously known visible tasks for purposes of loading/unloading task data @@ -327,7 +327,7 @@ public abstract class RecentsView extends PagedView impl mActivity = (T) BaseActivity.fromContext(context); mModel = RecentsModel.INSTANCE.get(context); mIdp = InvariantDeviceProfile.INSTANCE.get(context); - mTempClipAnimationHelper = new ClipAnimationHelper(context); + mTempAppWindowAnimationHelper = new AppWindowAnimationHelper(context); mClearAllButton = (ClearAllButton) LayoutInflater.from(context) .inflate(R.layout.overview_clear_all_button, this, false); @@ -808,7 +808,7 @@ public abstract class RecentsView extends PagedView impl mTaskListChangeId = -1; mRecentsAnimationWrapper = null; - mClipAnimationHelper = null; + mAppWindowAnimationHelper = null; unloadVisibleTaskData(); setCurrentPage(0); @@ -1519,14 +1519,14 @@ public abstract class RecentsView extends PagedView impl * to the right. */ public AnimatorSet createAdjacentPageAnimForTaskLaunch( - TaskView tv, ClipAnimationHelper clipAnimationHelper) { + TaskView tv, AppWindowAnimationHelper appWindowAnimationHelper) { AnimatorSet anim = new AnimatorSet(); int taskIndex = indexOfChild(tv); int centerTaskIndex = getCurrentPage(); boolean launchingCenterTask = taskIndex == centerTaskIndex; - LauncherState.ScaleAndTranslation toScaleAndTranslation = clipAnimationHelper + LauncherState.ScaleAndTranslation toScaleAndTranslation = appWindowAnimationHelper .getScaleAndTranslation(); float toScale = toScaleAndTranslation.scale; float toTranslationY = toScaleAndTranslation.translationY; @@ -1586,10 +1586,10 @@ public abstract class RecentsView extends PagedView impl } }); - ClipAnimationHelper clipAnimationHelper = new ClipAnimationHelper(mActivity); - clipAnimationHelper.fromTaskThumbnailView(tv.getThumbnail(), this); - clipAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */); - AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, clipAnimationHelper); + AppWindowAnimationHelper appWindowAnimationHelper = new AppWindowAnimationHelper(mActivity); + appWindowAnimationHelper.fromTaskThumbnailView(tv.getThumbnail(), this); + appWindowAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */); + AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, appWindowAnimationHelper); anim.play(progressAnim); anim.setDuration(duration); @@ -1696,8 +1696,8 @@ public abstract class RecentsView extends PagedView impl mRecentsAnimationWrapper = recentsAnimationWrapper; } - public void setClipAnimationHelper(ClipAnimationHelper clipAnimationHelper) { - mClipAnimationHelper = clipAnimationHelper; + public void setAppWindowAnimationHelper(AppWindowAnimationHelper appWindowAnimationHelper) { + mAppWindowAnimationHelper = appWindowAnimationHelper; } public void setLiveTileOverlay(LiveTileOverlay liveTileOverlay) { @@ -1805,15 +1805,15 @@ public abstract class RecentsView extends PagedView impl } } - public ClipAnimationHelper getClipAnimationHelper() { - return mClipAnimationHelper; + public AppWindowAnimationHelper getClipAnimationHelper() { + return mAppWindowAnimationHelper; } - public ClipAnimationHelper getTempClipAnimationHelper() { - return mTempClipAnimationHelper; + public AppWindowAnimationHelper getTempAppWindowAnimationHelper() { + return mTempAppWindowAnimationHelper; } - public ClipAnimationHelper.TransformParams getLiveTileParams( + public AppWindowAnimationHelper.TransformParams getLiveTileParams( boolean mightNeedToRefill) { return null; } diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java index 7cd87860ac..af75364023 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -71,7 +71,7 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteAnimationTargets; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.QuickStepContract; @@ -433,7 +433,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans Rect crop = new Rect(); Matrix matrix = new Matrix(); - RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(appTargets, + RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING); SyncRtSurfaceTransactionApplierCompat surfaceApplier = new SyncRtSurfaceTransactionApplierCompat(floatingView); diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 27b94f039b..5fb5fd72c1 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -33,7 +33,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteAnimationTargets; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -112,7 +112,7 @@ public interface ActivityControlHelper { public final boolean shouldPreformHaptic; } - default void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { } + default void onRemoteAnimationReceived(RemoteAnimationTargets targets) { } void createActivityController(long transitionLength); diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java similarity index 96% rename from quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java rename to quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java index d769248b2b..ff726a1efe 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java @@ -25,7 +25,7 @@ import java.util.Queue; /** * Holds a collection of RemoteAnimationTargets, filtered by different properties. */ -public class RemoteAnimationTargetSet { +public class RemoteAnimationTargets { private final Queue mDependentTransactionAppliers = new ArrayDeque<>(1); @@ -36,7 +36,7 @@ public class RemoteAnimationTargetSet { public final int targetMode; public final boolean hasRecents; - public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, + public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers, int targetMode) { ArrayList filteredApps = new ArrayList<>(); boolean hasRecents = false; diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java index 1d0851c493..7f6aba9925 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java +++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java @@ -29,12 +29,12 @@ import com.android.systemui.shared.system.TransactionCompat; */ public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener { - private final RemoteAnimationTargetSet mTarget; + private final RemoteAnimationTargets mTarget; private boolean mFirstFrame = true; public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets) { - mTarget = new RemoteAnimationTargetSet(appTargets, wallpaperTargets, MODE_CLOSING); + mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING); } @Override From 75eb0e0f20c6f4dd6bc0b7c9084f879f7267251b Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 1 Oct 2019 10:07:09 -0700 Subject: [PATCH 088/109] 2/ Move device state logic to its own class - Feed the class down to the input consumers and related gesture classes instead of specific sysui state flags Bug: 141886704 Change-Id: I2ade7f48555c9d0ba0d3fac5c1f2dae694624224 --- .../quickstep/TouchInteractionService.java | 38 +- .../LauncherActivityControllerHelper.java | 5 +- .../QuickstepTestInformationHandler.java | 5 +- .../quickstep/TouchInteractionService.java | 294 +++--------- .../WindowTransformSwipeHandler.java | 14 +- .../AccessibilityInputConsumer.java | 22 +- .../DeviceLockedInputConsumer.java | 14 +- .../OtherActivityInputConsumer.java | 16 +- .../quickstep/ActivityControlHelper.java | 3 +- .../quickstep/OverviewComponentObserver.java | 18 +- .../quickstep/OverviewInteractionState.java | 1 + .../RecentsAnimationDeviceState.java | 426 ++++++++++++++++++ 12 files changed, 546 insertions(+), 310 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java index 19dd82f7f7..6b936cbfc0 100644 --- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -34,6 +34,8 @@ import android.view.MotionEvent; import com.android.launcher3.Utilities; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.util.DefaultDisplay; +import com.android.quickstep.RecentsAnimationDeviceState; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; @@ -44,15 +46,6 @@ import com.android.systemui.shared.recents.ISystemUiProxy; public class TouchInteractionService extends Service { private static final String TAG = "GoTouchInteractionService"; - private boolean mIsUserUnlocked; - private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { - initWhenUserUnlocked(); - } - } - }; private final IBinder mMyBinder = new IOverviewProxy.Stub() { @@ -68,21 +61,21 @@ public class TouchInteractionService extends Service { @Override public void onOverviewToggle() { - if (mIsUserUnlocked) { + if (mDeviceState.isUserUnlocked()) { mOverviewCommandHelper.onOverviewToggle(); } } @Override public void onOverviewShown(boolean triggeredFromAltTab) { - if (mIsUserUnlocked) { + if (mDeviceState.isUserUnlocked()) { mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab); } } @Override public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { - if (mIsUserUnlocked && triggeredFromAltTab && !triggeredFromHomeKey) { + if (mDeviceState.isUserUnlocked() && triggeredFromAltTab && !triggeredFromHomeKey) { // onOverviewShownFromAltTab hides the overview and ends at the target app mOverviewCommandHelper.onOverviewHidden(); } @@ -90,7 +83,7 @@ public class TouchInteractionService extends Service { @Override public void onTip(int actionType, int viewType) { - if (mIsUserUnlocked) { + if (mDeviceState.isUserUnlocked()) { mOverviewCommandHelper.onTip(actionType, viewType); } } @@ -140,35 +133,30 @@ public class TouchInteractionService extends Service { private RecentsModel mRecentsModel; private OverviewComponentObserver mOverviewComponentObserver; private OverviewCommandHelper mOverviewCommandHelper; + private RecentsAnimationDeviceState mDeviceState; @Override public void onCreate() { super.onCreate(); - if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) { - initWhenUserUnlocked(); - } else { - mIsUserUnlocked = false; - registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); - } + mDeviceState = new RecentsAnimationDeviceState(this); + mDeviceState.runOnUserUnlocked(this::onUserUnlocked); sConnected = true; } - private void initWhenUserUnlocked() { + public void onUserUnlocked() { mRecentsModel = RecentsModel.INSTANCE.get(this); - mOverviewComponentObserver = new OverviewComponentObserver(this); + mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver); - mIsUserUnlocked = true; - Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); } @Override public void onDestroy() { - if (mIsUserUnlocked) { + if (mDeviceState.isUserUnlocked()) { mOverviewComponentObserver.onDestroy(); } - Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); + mDeviceState.destroy(); sConnected = false; super.onDestroy(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index bb735219d1..c749761eb9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -38,7 +38,6 @@ import android.animation.TimeInterpolator; import android.content.Context; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.Region; import android.os.UserHandle; import android.view.MotionEvent; import android.view.View; @@ -441,8 +440,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe } @Override - public boolean deferStartingActivity(Region activeNavBarRegion, MotionEvent ev) { - return activeNavBarRegion.contains((int) ev.getX(), (int) ev.getY()); + public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) { + return deviceState.isInDeferredGestureRegion(ev); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index c4f375a124..6ac75465a3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -5,10 +5,12 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.content.Context; import android.os.Bundle; +import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.testing.TestInformationHandler; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController; +import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; @@ -78,7 +80,8 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { } private RecentsView getRecentsView() { - OverviewComponentObserver observer = new OverviewComponentObserver(mContext); + OverviewComponentObserver observer = new OverviewComponentObserver(mContext, + new RecentsAnimationDeviceState(mContext)); try { return observer.getActivityControlHelper().getCreatedActivity().getOverviewPanel(); } finally { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 3b48fa7014..4ca80556d6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -27,15 +27,6 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT; import android.annotation.TargetApi; @@ -43,44 +34,31 @@ import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.Service; import android.app.TaskInfo; -import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Configuration; -import android.graphics.Point; -import android.graphics.RectF; import android.graphics.Region; import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Looper; -import android.os.Process; import android.os.RemoteException; -import android.text.TextUtils; import android.util.Log; import android.view.Choreographer; import android.view.InputEvent; import android.view.MotionEvent; -import android.view.Surface; -import androidx.annotation.BinderThread; import androidx.annotation.UiThread; import androidx.annotation.WorkerThread; import com.android.launcher3.BaseDraggingActivity; -import com.android.launcher3.R; -import com.android.launcher3.ResourceUtils; import com.android.launcher3.Utilities; -import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.logging.EventLogArray; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.uioverrides.DejankBinderTracker; -import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; @@ -99,10 +77,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; -import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; import com.android.systemui.shared.system.RecentsAnimationListener; -import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat; import com.android.systemui.shared.system.TaskInfoCompat; import java.io.FileDescriptor; @@ -133,7 +108,7 @@ class ArgList extends LinkedList { */ @TargetApi(Build.VERSION_CODES.Q) public class TouchInteractionService extends Service implements - NavigationModeChangeListener, DefaultDisplay.DisplayInfoChangeListener { + NavigationModeChangeListener { /** * NOTE: This value should be kept same as @@ -154,10 +129,6 @@ public class TouchInteractionService extends Service implements private final IBinder mMyBinder = new IOverviewProxy.Stub() { - public void onActiveNavBarRegionChanges(Region region) { - mActiveNavBarRegion = region; - } - public void onInitialize(Bundle bundle) { mISystemUiProxy = ISystemUiProxy.Stub .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); @@ -192,14 +163,14 @@ public class TouchInteractionService extends Service implements @Override public void onAssistantAvailable(boolean available) { - mAssistantAvailable = available; + MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantAvailable(available)); + MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged); } @Override public void onAssistantVisibilityChanged(float visibility) { - mLastAssistantVisibility = visibility; - MAIN_EXECUTOR.execute( - TouchInteractionService.this::onAssistantVisibilityChanged); + MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantVisibility(visibility)); + MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged); } public void onBackAction(boolean completed, int downX, int downY, boolean isButton, @@ -219,10 +190,14 @@ public class TouchInteractionService extends Service implements } public void onSystemUiStateChanged(int stateFlags) { - mSystemUiStateFlags = stateFlags; + MAIN_EXECUTOR.execute(() -> mDeviceState.setSystemUiFlags(stateFlags)); MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged); } + public void onActiveNavBarRegionChanges(Region region) { + MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region)); + } + /** Deprecated methods **/ public void onQuickStep(MotionEvent motionEvent) { } @@ -272,71 +247,28 @@ public class TouchInteractionService extends Service implements private OverviewCommandHelper mOverviewCommandHelper; private OverviewComponentObserver mOverviewComponentObserver; private OverviewInteractionState mOverviewInteractionState; - private TaskOverlayFactory mTaskOverlayFactory; private InputConsumerController mInputConsumer; - private boolean mAssistantAvailable; - private float mLastAssistantVisibility = 0; - private @SystemUiStateFlags int mSystemUiStateFlags; - - private boolean mIsUserUnlocked; - private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { - initWhenUserUnlocked(); - } - } - }; + private RecentsAnimationDeviceState mDeviceState; private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP; private InputConsumer mConsumer = InputConsumer.NO_OP; private Choreographer mMainChoreographer; - private Region mActiveNavBarRegion = new Region(); - private InputMonitorCompat mInputMonitorCompat; private InputEventReceiver mInputEventReceiver; private Mode mMode = Mode.THREE_BUTTONS; - private int mDefaultDisplayId; - private final RectF mSwipeTouchRegion = new RectF(); - private final RectF mAssistantLeftRegion = new RectF(); - private final RectF mAssistantRightRegion = new RectF(); - - private ComponentName mGestureBlockingActivity; - - private Region mExclusionRegion; - private SystemGestureExclusionListenerCompat mExclusionListener; @Override public void onCreate() { super.onCreate(); + mDeviceState = new RecentsAnimationDeviceState(this); + mDeviceState.runOnUserUnlocked(this::onUserUnlocked); // Initialize anything here that is needed in direct boot mode. - // Everything else should be initialized in initWhenUserUnlocked() below. + // Everything else should be initialized in onUserUnlocked() below. mMainChoreographer = Choreographer.getInstance(); mAM = ActivityManagerWrapper.getInstance(); - if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) { - initWhenUserUnlocked(); - } else { - mIsUserUnlocked = false; - registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); - } - - mDefaultDisplayId = DefaultDisplay.INSTANCE.get(this).getInfo().id; - String blockingActivity = getString(R.string.gesture_blocking_activity); - mGestureBlockingActivity = TextUtils.isEmpty(blockingActivity) ? null : - ComponentName.unflattenFromString(blockingActivity); - - mExclusionListener = new SystemGestureExclusionListenerCompat(mDefaultDisplayId) { - @Override - @BinderThread - public void onExclusionChanged(Region region) { - // Assignments are atomic, it should be safe on binder thread - mExclusionRegion = region; - } - }; - onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this)); sConnected = true; } @@ -359,17 +291,18 @@ public class TouchInteractionService extends Service implements if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 1"); } + disposeEventHandlers(); if (!mMode.hasGestures || mISystemUiProxy == null) { return; } - disposeEventHandlers(); if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 2"); } try { mInputMonitorCompat = InputMonitorCompat.fromBundle(mISystemUiProxy - .monitorGestureInput("swipe-up", mDefaultDisplayId), KEY_EXTRA_INPUT_MONITOR); + .monitorGestureInput("swipe-up", mDeviceState.getDisplayId()), + KEY_EXTRA_INPUT_MONITOR); mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(), mMainChoreographer, this::onInputEvent); if (TestProtocol.sDebugTracing) { @@ -378,55 +311,8 @@ public class TouchInteractionService extends Service implements } catch (RemoteException e) { Log.e(TAG, "Unable to create input monitor", e); } - initTouchBounds(); - } - private int getNavbarSize(String resName) { - return ResourceUtils.getNavbarSize(resName, getResources()); - } - - private void initTouchBounds() { - if (!mMode.hasGestures) { - return; - } - - DefaultDisplay.Info displayInfo = DefaultDisplay.INSTANCE.get(this).getInfo(); - Point realSize = new Point(displayInfo.realSize); - mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y); - if (mMode == Mode.NO_BUTTON) { - int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE); - mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - touchHeight; - - final int assistantWidth = getResources() - .getDimensionPixelSize(R.dimen.gestures_assistant_width); - final float assistantHeight = Math.max(touchHeight, - QuickStepContract.getWindowCornerRadius(getResources())); - mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeTouchRegion.bottom; - mAssistantLeftRegion.top = mAssistantRightRegion.top = - mSwipeTouchRegion.bottom - assistantHeight; - - mAssistantLeftRegion.left = 0; - mAssistantLeftRegion.right = assistantWidth; - - mAssistantRightRegion.right = mSwipeTouchRegion.right; - mAssistantRightRegion.left = mSwipeTouchRegion.right - assistantWidth; - } else { - mAssistantLeftRegion.setEmpty(); - mAssistantRightRegion.setEmpty(); - switch (displayInfo.rotation) { - case Surface.ROTATION_90: - mSwipeTouchRegion.left = mSwipeTouchRegion.right - - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE); - break; - case Surface.ROTATION_270: - mSwipeTouchRegion.right = mSwipeTouchRegion.left - + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE); - break; - default: - mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE); - } - } + mDeviceState.updateGestureTouchRegions(); } @Override @@ -434,43 +320,17 @@ public class TouchInteractionService extends Service implements if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "onNavigationModeChanged " + newMode); } - if (mMode.hasGestures != newMode.hasGestures) { - if (newMode.hasGestures) { - DefaultDisplay.INSTANCE.get(this).addChangeListener(this); - } else { - DefaultDisplay.INSTANCE.get(this).removeChangeListener(this); - } - } mMode = newMode; - - disposeEventHandlers(); initInputMonitor(); - - if (mMode == Mode.NO_BUTTON) { - mExclusionListener.register(); - } else { - mExclusionListener.unregister(); - } } - @Override - public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) { - if (info.id != mDefaultDisplayId) { - return; - } - - initTouchBounds(); - } - - private void initWhenUserUnlocked() { + public void onUserUnlocked() { mRecentsModel = RecentsModel.INSTANCE.get(this); - mOverviewComponentObserver = new OverviewComponentObserver(this); + mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver); mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this); - mTaskOverlayFactory = TaskOverlayFactory.INSTANCE.get(this); mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); - mIsUserUnlocked = true; sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver); mInputConsumer.registerInputConsumer(); @@ -482,13 +342,11 @@ public class TouchInteractionService extends Service implements // new ModelPreload().start(this); mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this) .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT)); - - Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); } @UiThread private void onSystemUiProxySet() { - if (mIsUserUnlocked) { + if (mDeviceState.isUserUnlocked()) { mRecentsModel.setSystemUiProxy(mISystemUiProxy); mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy); } @@ -496,37 +354,32 @@ public class TouchInteractionService extends Service implements @UiThread private void onSystemUiFlagsChanged() { - if (mIsUserUnlocked) { - mOverviewInteractionState.setSystemUiStateFlags(mSystemUiStateFlags); - mOverviewComponentObserver.onSystemUiStateChanged(mSystemUiStateFlags); + if (mDeviceState.isUserUnlocked()) { + mOverviewInteractionState.setSystemUiStateFlags(mDeviceState.getSystemUiStateFlags()); + mOverviewComponentObserver.onSystemUiStateChanged(); } } @UiThread private void onAssistantVisibilityChanged() { - if (mIsUserUnlocked) { + if (mDeviceState.isUserUnlocked()) { mOverviewComponentObserver.getActivityControlHelper().onAssistantVisibilityChanged( - mLastAssistantVisibility); + mDeviceState.getAssistantVisibility()); } } @Override public void onDestroy() { sIsInitialized = false; - if (mIsUserUnlocked) { + if (mDeviceState.isUserUnlocked()) { mInputConsumer.unregisterInputConsumer(); mOverviewComponentObserver.onDestroy(); } disposeEventHandlers(); - if (mMode.hasGestures) { - DefaultDisplay.INSTANCE.get(this).removeChangeListener(this); - } + SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this); + mDeviceState.destroy(); sConnected = false; - Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); - SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this); - mExclusionListener.unregister(); - super.onDestroy(); } @@ -551,14 +404,14 @@ public class TouchInteractionService extends Service implements mLogId = TOUCH_INTERACTION_LOG.generateAndSetLogId(); sSwipeSharedState.setLogTraceId(mLogId); - if (mSwipeTouchRegion.contains(event.getX(), event.getY())) { + if (mDeviceState.isInSwipeUpTouchRegion(event)) { boolean useSharedState = mConsumer.useSharedSwipeState(); mConsumer.onConsumerAboutToBeSwitched(); mConsumer = newConsumer(useSharedState, event); TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType()); mUncheckedConsumer = mConsumer; - } else if (mIsUserUnlocked && mMode == Mode.NO_BUTTON - && canTriggerAssistantAction(event)) { + } else if (mDeviceState.isUserUnlocked() && mMode == Mode.NO_BUTTON + && mDeviceState.canTriggerAssistantAction(event)) { // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should // not interrupt it. QuickSwitch assumes that interruption can only happen if the // next gesture is also quick switch. @@ -576,27 +429,11 @@ public class TouchInteractionService extends Service implements DejankBinderTracker.disallowBinderTrackingInTests(); } - private boolean validSystemUiFlags() { - return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 - && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0 - && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0 - && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 - || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0); - } - - private boolean canTriggerAssistantAction(MotionEvent ev) { - return mAssistantAvailable - && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags) - && (mAssistantLeftRegion.contains(ev.getX(), ev.getY()) || - mAssistantRightRegion.contains(ev.getX(), ev.getY())) - && !ActivityManagerWrapper.getInstance().isLockToAppActive(); - } - private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) { - boolean isInValidSystemUiState = validSystemUiFlags(); + boolean canStartSystemGesture = mDeviceState.canStartSystemGesture(); - if (!mIsUserUnlocked) { - if (isInValidSystemUiState) { + if (!mDeviceState.isUserUnlocked()) { + if (canStartSystemGesture) { // This handles apps launched in direct boot mode (e.g. dialer) as well as apps // launched while device is locked even after exiting direct boot mode (e.g. camera). return createDeviceLockedInputConsumer(mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT)); @@ -607,29 +444,28 @@ public class TouchInteractionService extends Service implements // When using sharedState, bypass systemState check as this is a followup gesture and the // first gesture started in a valid system state. - InputConsumer base = isInValidSystemUiState || useSharedState + InputConsumer base = canStartSystemGesture || useSharedState ? newBaseConsumer(useSharedState, event) : mResetGestureInputConsumer; if (mMode == Mode.NO_BUTTON) { final ActivityControlHelper activityControl = mOverviewComponentObserver.getActivityControlHelper(); - if (canTriggerAssistantAction(event)) { + if (mDeviceState.canTriggerAssistantAction(event)) { base = new AssistantInputConsumer(this, mISystemUiProxy, activityControl, base, mInputMonitorCompat); } - if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) { + if (mDeviceState.isScreenPinningActive()) { // Note: we only allow accessibility to wrap this, and it replaces the previous // base input consumer (which should be NO_OP anyway since topTaskLocked == true). base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl); } - if ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0) { - base = new AccessibilityInputConsumer(this, mISystemUiProxy, - (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0, base, - mInputMonitorCompat, mSwipeTouchRegion); + if (mDeviceState.isAccessibilityMenuAvailable()) { + base = new AccessibilityInputConsumer(this, mDeviceState, mISystemUiProxy, base, + mInputMonitorCompat); } } else { - if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) { + if (mDeviceState.isScreenPinningActive()) { base = mResetGestureInputConsumer; } } @@ -642,7 +478,7 @@ public class TouchInteractionService extends Service implements if (!useSharedState) { sSwipeSharedState.clearAllState(false /* finishAnimation */); } - if ((mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0) { + if (mDeviceState.isKeyguardShowingOccluded()) { // This handles apps showing over the lockscreen (e.g. camera) return createDeviceLockedInputConsumer(runningTaskInfo); } @@ -678,8 +514,7 @@ public class TouchInteractionService extends Service implements return createOverviewInputConsumer(event); } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) { return createOverviewInputConsumer(event); - } else if (mGestureBlockingActivity != null && runningTaskInfo != null - && mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) { + } else if (mDeviceState.isGestureBlockedActivity(runningTaskInfo)) { return mResetGestureInputConsumer; } else { return createOtherActivityInputConsumer(event, runningTaskInfo); @@ -692,13 +527,6 @@ public class TouchInteractionService extends Service implements && (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; } - private boolean disableHorizontalSwipe(MotionEvent event) { - // mExclusionRegion can change on binder thread, use a local instance here. - Region exclusionRegion = mExclusionRegion; - return mMode == Mode.NO_BUTTON && exclusionRegion != null - && exclusionRegion.contains((int) event.getX(), (int) event.getY()); - } - private InputConsumer createOtherActivityInputConsumer(MotionEvent event, RunningTaskInfo runningTaskInfo) { @@ -711,19 +539,20 @@ public class TouchInteractionService extends Service implements shouldDefer = !sSwipeSharedState.recentsAnimationFinishInterrupted; factory = mFallbackNoButtonFactory; } else { - shouldDefer = activityControlHelper.deferStartingActivity(mActiveNavBarRegion, event); + shouldDefer = activityControlHelper.deferStartingActivity(mDeviceState, event); factory = mWindowTreansformFactory; } - return new OtherActivityInputConsumer(this, runningTaskInfo, shouldDefer, - this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion, - disableHorizontalSwipe(event), activityControlHelper, factory, mLogId); + final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); + return new OtherActivityInputConsumer(this, mDeviceState, runningTaskInfo, shouldDefer, + this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat, + disableHorizontalSwipe, activityControlHelper, factory, mLogId); } private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) { if (mMode == Mode.NO_BUTTON && taskInfo != null) { - return new DeviceLockedInputConsumer(this, sSwipeSharedState, mInputMonitorCompat, - mSwipeTouchRegion, taskInfo.taskId, mLogId); + return new DeviceLockedInputConsumer(this, mDeviceState, sSwipeSharedState, + mInputMonitorCompat, taskInfo.taskId, mLogId); } else { return mResetGestureInputConsumer; } @@ -741,8 +570,9 @@ public class TouchInteractionService extends Service implements return new OverviewInputConsumer(activity, mInputMonitorCompat, false /* startingInActivityBounds */, activityControl); } else { + final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); return new OverviewWithoutFocusInputConsumer(activity, mInputMonitorCompat, - activityControl, disableHorizontalSwipe(event)); + activityControl, disableHorizontalSwipe); } } @@ -757,7 +587,7 @@ public class TouchInteractionService extends Service implements } private void preloadOverview(boolean fromInit) { - if (!mIsUserUnlocked) { + if (!mDeviceState.isUserUnlocked()) { return; } if (!mMode.hasGestures && !mOverviewComponentObserver.isHomeAndOverviewSame()) { @@ -793,7 +623,7 @@ public class TouchInteractionService extends Service implements @Override public void onConfigurationChanged(Configuration newConfig) { - if (!mIsUserUnlocked) { + if (!mDeviceState.isUserUnlocked()) { return; } final ActivityControlHelper activityControl = @@ -826,15 +656,9 @@ public class TouchInteractionService extends Service implements } } else { // Dump everything + mDeviceState.dump(pw); pw.println("TouchState:"); pw.println(" navMode=" + mMode); - pw.println(" validSystemUiFlags=" + validSystemUiFlags()); - pw.println(" systemUiFlags=" + mSystemUiStateFlags); - pw.println(" systemUiFlagsDesc=" - + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags)); - pw.println(" assistantAvailable=" + mAssistantAvailable); - pw.println(" assistantDisabled=" - + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)); boolean resumed = mOverviewComponentObserver != null && mOverviewComponentObserver.getActivityControlHelper().isResumed(); pw.println(" resumed=" + resumed); @@ -870,7 +694,7 @@ public class TouchInteractionService extends Service implements private BaseSwipeUpHandler createWindowTransformSwipeHandler(RunningTaskInfo runningTask, long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) { - return new WindowTransformSwipeHandler(runningTask, this, touchTimeMs, + return new WindowTransformSwipeHandler(mDeviceState, runningTask, this, touchTimeMs, mOverviewComponentObserver, continuingLastGesture, mInputConsumer, mRecentsModel); } @@ -882,7 +706,7 @@ public class TouchInteractionService extends Service implements protected boolean shouldNotifyBackGesture() { return mBackGestureNotificationCounter > 0 && - mGestureBlockingActivity != null; + mDeviceState.getGestureBlockedActivityPackage() != null; } @WorkerThread @@ -892,7 +716,7 @@ public class TouchInteractionService extends Service implements Utilities.getDevicePrefs(this).edit() .putInt(KEY_BACK_NOTIFICATION_COUNT, mBackGestureNotificationCounter).apply(); sendBroadcast(new Intent(NOTIFY_ACTION_BACK).setPackage( - mGestureBlockingActivity.getPackageName())); + mDeviceState.getGestureBlockedActivityPackage())); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index fd1ed626e0..5cf987ad6c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -35,7 +35,6 @@ import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK; import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.RECENTS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.animation.Animator; import android.animation.AnimatorSet; @@ -198,6 +197,8 @@ public class WindowTransformSwipeHandler */ private static final int LOG_NO_OP_PAGE_INDEX = -1; + private RecentsAnimationDeviceState mDeviceState; + private GestureEndTarget mGestureEndTarget; // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise private RunningWindowAnim mRunningWindowAnim; @@ -229,11 +230,12 @@ public class WindowTransformSwipeHandler private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; - public WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, - long touchTimeMs, OverviewComponentObserver overviewComponentObserver, - boolean continuingLastGesture, + public WindowTransformSwipeHandler(RecentsAnimationDeviceState deviceState, + RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, + OverviewComponentObserver overviewComponentObserver, boolean continuingLastGesture, InputConsumerController inputConsumer, RecentsModel recentsModel) { super(context, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id); + mDeviceState = deviceState; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; initStateCallbacks(); @@ -755,9 +757,7 @@ public class WindowTransformSwipeHandler } } - int stateFlags = OverviewInteractionState.INSTANCE.get(mActivity).getSystemUiStateFlags(); - if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 - && (endTarget == RECENTS || endTarget == LAST_TASK)) { + if (mDeviceState.isOverviewDisabled() && (endTarget == RECENTS || endTarget == LAST_TASK)) { return LAST_TASK; } return endTarget; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java index 1f73a28eff..92bcfb5fda 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java @@ -23,7 +23,6 @@ import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import android.content.Context; -import android.graphics.RectF; import android.os.RemoteException; import android.util.Log; import android.view.Display; @@ -32,12 +31,13 @@ import android.view.VelocityTracker; import android.view.ViewConfiguration; import com.android.launcher3.R; +import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.util.MotionPauseDetector; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.InputMonitorCompat; /** - * Touch consumer for two finger swipe actions for accessibility actions + * Input consumer for two finger swipe actions for accessibility actions */ public class AccessibilityInputConsumer extends DelegateInputConsumer { @@ -46,8 +46,7 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { private final ISystemUiProxy mSystemUiProxy; private final VelocityTracker mVelocityTracker; private final MotionPauseDetector mMotionPauseDetector; - private final boolean mAllowLongClick; - private final RectF mSwipeTouchRegion; + private final RecentsAnimationDeviceState mDeviceState; private final float mMinGestureDistance; private final float mMinFlingVelocity; @@ -56,19 +55,17 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { private float mDownY; private float mTotalY; - public AccessibilityInputConsumer(Context context, ISystemUiProxy systemUiProxy, - boolean allowLongClick, InputConsumer delegate, InputMonitorCompat inputMonitor, - RectF swipeTouchRegion) { + public AccessibilityInputConsumer(Context context, RecentsAnimationDeviceState deviceState, + ISystemUiProxy systemUiProxy, InputConsumer delegate, InputMonitorCompat inputMonitor) { super(delegate, inputMonitor); mSystemUiProxy = systemUiProxy; mVelocityTracker = VelocityTracker.obtain(); mMinGestureDistance = context.getResources() .getDimension(R.dimen.accessibility_gesture_min_swipe_distance); mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity(); - mSwipeTouchRegion = swipeTouchRegion; + mDeviceState = deviceState; mMotionPauseDetector = new MotionPauseDetector(context); - mAllowLongClick = allowLongClick; } @Override @@ -103,7 +100,7 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { case ACTION_POINTER_DOWN: { if (mState == STATE_INACTIVE) { int pointerIndex = ev.getActionIndex(); - if (mSwipeTouchRegion.contains(ev.getX(pointerIndex), ev.getY(pointerIndex)) + if (mDeviceState.isInSwipeUpTouchRegion(ev, pointerIndex) && mDelegate.allowInterceptByParent()) { setActive(ev); @@ -116,7 +113,7 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { break; } case ACTION_MOVE: { - if (mState == STATE_ACTIVE && mAllowLongClick) { + if (mState == STATE_ACTIVE && mDeviceState.isAccessibilityMenuShortcutAvailable()) { int pointerIndex = ev.findPointerIndex(mActivePointerId); if (pointerIndex == -1) { break; @@ -130,7 +127,8 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { case ACTION_UP: if (mState == STATE_ACTIVE) { try { - if (mAllowLongClick && mMotionPauseDetector.isPaused()) { + if (mDeviceState.isAccessibilityMenuShortcutAvailable() + && mMotionPauseDetector.isPaused()) { mSystemUiProxy.notifyAccessibilityButtonLongClicked(); } else { mTotalY += (ev.getY() - mDownY); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 536470bb01..ba2d6d133c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -32,7 +32,6 @@ import android.content.Intent; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.RectF; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; @@ -42,6 +41,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; +import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.RecentsAnimationCallbacks; @@ -73,6 +73,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, getFlagForIndex(1, "STATE_HANDLER_INVALIDATED"); private final Context mContext; + private final RecentsAnimationDeviceState mDeviceState; private final float mTouchSlopSquared; private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; @@ -83,7 +84,6 @@ public class DeviceLockedInputConsumer implements InputConsumer, private final AppWindowAnimationHelper.TransformParams mTransformParams; private final Point mDisplaySize; private final MultiStateCallback mStateCallback; - private final RectF mSwipeTouchRegion; public final int mRunningTaskId; private VelocityTracker mVelocityTracker; @@ -93,17 +93,17 @@ public class DeviceLockedInputConsumer implements InputConsumer, private RecentsAnimationTargets mTargetSet; - public DeviceLockedInputConsumer(Context context, SwipeSharedState swipeSharedState, - InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId, - int logId) { + public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState, + SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, + int runningTaskId, int logId) { mContext = context; + mDeviceState = deviceState; mTouchSlopSquared = squaredTouchSlop(context); mSwipeSharedState = swipeSharedState; mAppWindowAnimationHelper = new AppWindowAnimationHelper(context); mLogId = logId; mTransformParams = new AppWindowAnimationHelper.TransformParams(); mInputMonitorCompat = inputMonitorCompat; - mSwipeTouchRegion = swipeTouchRegion; mRunningTaskId = runningTaskId; // Do not use DeviceProfile as the user data might be locked @@ -139,7 +139,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, if (!mThresholdCrossed) { // Cancel interaction in case of multi-touch interaction int ptrIdx = ev.getActionIndex(); - if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) { + if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) { int action = ev.getAction(); ev.setAction(ACTION_CANCEL); finishTouchTracking(ev); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index e4d898b952..6776e84d27 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -38,7 +38,6 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.graphics.PointF; -import android.graphics.RectF; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -55,6 +54,7 @@ import com.android.launcher3.util.TraceHelper; import com.android.quickstep.ActivityControlHelper; import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.BaseSwipeUpHandler.Factory; +import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; @@ -79,12 +79,12 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // TODO: Move to quickstep contract public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3; + private final RecentsAnimationDeviceState mDeviceState; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final RunningTaskInfo mRunningTask; private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; private final SysUINavigationMode.Mode mMode; - private final RectF mSwipeTouchRegion; private final ActivityControlHelper mActivityControlHelper; private final BaseSwipeUpHandler.Factory mHandlerFactory; @@ -124,19 +124,19 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC }; private int mLogId; - public OtherActivityInputConsumer(Context base, RunningTaskInfo runningTaskInfo, - boolean isDeferredDownTarget, Consumer onCompleteCallback, + public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, + RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget, + Consumer onCompleteCallback, SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, - RectF swipeTouchRegion, boolean disableHorizontalSwipe, - ActivityControlHelper activityControlHelper, + boolean disableHorizontalSwipe, ActivityControlHelper activityControlHelper, Factory handlerFactory, int logId) { super(base); mLogId = logId; + mDeviceState = deviceState; mMainThreadHandler = new Handler(Looper.getMainLooper()); mRunningTask = runningTaskInfo; mMode = SysUINavigationMode.getMode(base); - mSwipeTouchRegion = swipeTouchRegion; mHandlerFactory = handlerFactory; mActivityControlHelper = activityControlHelper; @@ -217,7 +217,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC if (!mPassedPilferInputSlop) { // Cancel interaction in case of multi-touch interaction int ptrIdx = ev.getActionIndex(); - if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) { + if (!mDeviceState.isInSwipeUpTouchRegion(ev, ptrIdx)) { forceCancelGesture(ev); } } diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 5fb5fd72c1..132d6abe14 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -19,7 +19,6 @@ import android.annotation.TargetApi; import android.content.Context; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.Region; import android.os.Build; import android.view.MotionEvent; import android.view.View; @@ -81,7 +80,7 @@ public interface ActivityControlHelper { boolean shouldMinimizeSplitScreen(); - default boolean deferStartingActivity(Region activeNavBarRegion, MotionEvent ev) { + default boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) { return true; } diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java index 88a4eb6d11..331183a512 100644 --- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java +++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java @@ -22,7 +22,6 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter; import static com.android.systemui.shared.system.PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -57,6 +56,7 @@ public final class OverviewComponentObserver { } }; private final Context mContext; + private final RecentsAnimationDeviceState mDeviceState; private final Intent mCurrentHomeIntent; private final Intent mMyHomeIntent; private final Intent mFallbackIntent; @@ -64,12 +64,13 @@ public final class OverviewComponentObserver { private String mUpdateRegisteredPackage; private ActivityControlHelper mActivityControlHelper; private Intent mOverviewIntent; - private int mSystemUiStateFlags; private boolean mIsHomeAndOverviewSame; private boolean mIsDefaultHome; + private boolean mIsHomeDisabled; - public OverviewComponentObserver(Context context) { + public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) { mContext = context; + mDeviceState = deviceState; mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) @@ -98,11 +99,8 @@ public final class OverviewComponentObserver { updateOverviewTargets(); } - public void onSystemUiStateChanged(int stateFlags) { - boolean homeDisabledChanged = (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) - != (stateFlags & SYSUI_STATE_HOME_DISABLED); - mSystemUiStateFlags = stateFlags; - if (homeDisabledChanged) { + public void onSystemUiStateChanged() { + if (mDeviceState.isHomeDisabled() != mIsHomeDisabled) { updateOverviewTargets(); } } @@ -115,6 +113,7 @@ public final class OverviewComponentObserver { ComponentName defaultHome = PackageManagerWrapper.getInstance() .getHomeActivities(new ArrayList<>()); + mIsHomeDisabled = mDeviceState.isHomeDisabled(); mIsDefaultHome = Objects.equals(mMyHomeIntent.getComponent(), defaultHome); // Set assistant visibility to 0 from launcher's perspective, ensures any elements that @@ -124,8 +123,7 @@ public final class OverviewComponentObserver { mActivityControlHelper.onAssistantVisibilityChanged(0.f); } - if ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 - && (defaultHome == null || mIsDefaultHome)) { + if (!mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) { // User default home is same as out home app. Use Overview integrated in Launcher. mActivityControlHelper = new LauncherActivityControllerHelper(); mIsHomeAndOverviewSame = true; diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java index 858c3b6b3f..17462ab6b3 100644 --- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java +++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java @@ -86,6 +86,7 @@ public class OverviewInteractionState { mBgHandler.obtainMessage(MSG_SET_PROXY, proxy).sendToTarget(); } + // TODO(141886704): See if we can remove this public void setSystemUiStateFlags(int stateFlags) { mSystemUiStateFlags = stateFlags; } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java new file mode 100644 index 0000000000..9b094f6e2d --- /dev/null +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -0,0 +1,426 @@ +/* + * 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.quickstep; + +import static android.content.Intent.ACTION_USER_UNLOCKED; +import static com.android.launcher3.ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE; +import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE; +import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; +import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; + +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.Resources; +import android.graphics.Point; +import android.graphics.RectF; +import android.graphics.Region; +import android.os.Process; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.Surface; +import androidx.annotation.BinderThread; +import com.android.launcher3.R; +import com.android.launcher3.ResourceUtils; +import com.android.launcher3.Utilities; +import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.util.DefaultDisplay; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; +import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat; +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * Manages the state of the system during a swipe up gesture. + */ +public class RecentsAnimationDeviceState implements + SysUINavigationMode.NavigationModeChangeListener, + DefaultDisplay.DisplayInfoChangeListener { + + private Context mContext; + private UserManagerCompat mUserManager; + private SysUINavigationMode mSysUiNavMode; + private DefaultDisplay mDefaultDisplay; + private int mDisplayId; + + private @SystemUiStateFlags int mSystemUiStateFlags; + private SysUINavigationMode.Mode mMode = THREE_BUTTONS; + + private final RectF mSwipeUpTouchRegion = new RectF(); + private final Region mDeferredGestureRegion = new Region(); + private final RectF mAssistantLeftRegion = new RectF(); + private final RectF mAssistantRightRegion = new RectF(); + private boolean mAssistantAvailable; + private float mAssistantVisibility; + + private boolean mIsUserUnlocked; + private final ArrayList mUserUnlockedActions = new ArrayList<>(); + private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_USER_UNLOCKED.equals(intent.getAction())) { + mIsUserUnlocked = true; + notifyUserUnlocked(); + } + } + }; + + private Region mExclusionRegion; + private SystemGestureExclusionListenerCompat mExclusionListener; + + private ComponentName mGestureBlockedActivity; + + public RecentsAnimationDeviceState(Context context) { + mContext = context; + mUserManager = UserManagerCompat.getInstance(context); + mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context); + mDefaultDisplay = DefaultDisplay.INSTANCE.get(context); + mDisplayId = mDefaultDisplay.getInfo().id; + + // Register for user unlocked if necessary + mIsUserUnlocked = mUserManager.isUserUnlocked(Process.myUserHandle()); + if (!mIsUserUnlocked) { + mContext.registerReceiver(mUserUnlockedReceiver, + new IntentFilter(ACTION_USER_UNLOCKED)); + } + + // Register for exclusion updates + mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) { + @Override + @BinderThread + public void onExclusionChanged(Region region) { + // Assignments are atomic, it should be safe on binder thread + mExclusionRegion = region; + } + }; + onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this)); + + // Add any blocked activities + String blockingActivity = context.getString(R.string.gesture_blocking_activity); + if (!TextUtils.isEmpty(blockingActivity)) { + mGestureBlockedActivity = ComponentName.unflattenFromString(blockingActivity); + } + } + + /** + * Cleans up all the registered listeners and receivers. + */ + public void destroy() { + Utilities.unregisterReceiverSafely(mContext, mUserUnlockedReceiver); + mSysUiNavMode.removeModeChangeListener(this); + mDefaultDisplay.removeChangeListener(this); + mExclusionListener.unregister(); + } + + @Override + public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) { + mDefaultDisplay.removeChangeListener(this); + if (newMode.hasGestures) { + mDefaultDisplay.addChangeListener(this); + } + + if (mMode == NO_BUTTON) { + mExclusionListener.register(); + } else { + mExclusionListener.unregister(); + } + mMode = newMode; + } + + @Override + public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) { + if (info.id != getDisplayId()) { + return; + } + + updateGestureTouchRegions(); + } + + /** + * @return the display id for the display that Launcher is running on. + */ + public int getDisplayId() { + return mDisplayId; + } + + /** + * Adds a callback for when a user is unlocked. If the user is already unlocked, this listener + * will be called back immediately. + */ + public void runOnUserUnlocked(Runnable action) { + if (mIsUserUnlocked) { + action.run(); + } else { + mUserUnlockedActions.add(action); + } + } + + /** + * @return whether the user is unlocked. + */ + public boolean isUserUnlocked() { + return mIsUserUnlocked; + } + + private void notifyUserUnlocked() { + for (Runnable action : mUserUnlockedActions) { + action.run(); + } + mUserUnlockedActions.clear(); + Utilities.unregisterReceiverSafely(mContext, mUserUnlockedReceiver); + } + + /** + * @return whether the given running task info matches the gesture-blocked activity. + */ + public boolean isGestureBlockedActivity(ActivityManager.RunningTaskInfo runningTaskInfo) { + return runningTaskInfo != null + && mGestureBlockedActivity.equals(runningTaskInfo.topActivity); + } + + /** + * @return the package of the gesture-blocked activity or {@code null} if there is none. + */ + public String getGestureBlockedActivityPackage() { + return (mGestureBlockedActivity != null) + ? mGestureBlockedActivity.getPackageName() + : null; + } + + /** + * Updates the system ui state flags from SystemUI. + */ + public void setSystemUiFlags(int stateFlags) { + mSystemUiStateFlags = stateFlags; + } + + /** + * @return the system ui state flags. + */ + // TODO(141886704): See if we can remove this + public @SystemUiStateFlags int getSystemUiStateFlags() { + return mSystemUiStateFlags; + } + + /** + * @return whether SystemUI is in a state where we can start a system gesture. + */ + public boolean canStartSystemGesture() { + return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 + && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0 + && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0 + && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 + || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0); + } + + /** + * @return whether the keyguard is showing and is occluded by an app showing above the keyguard + * (like camera or maps) + */ + public boolean isKeyguardShowingOccluded() { + return (mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0; + } + + /** + * @return whether screen pinning is enabled and active + */ + public boolean isScreenPinningActive() { + return (mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0; + } + + /** + * @return whether lock-task mode is active + */ + public boolean isLockToAppActive() { + return ActivityManagerWrapper.getInstance().isLockToAppActive(); + } + + /** + * @return whether the accessibility menu is available. + */ + public boolean isAccessibilityMenuAvailable() { + return (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0; + } + + /** + * @return whether the accessibility menu shortcut is available. + */ + public boolean isAccessibilityMenuShortcutAvailable() { + return (mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0; + } + + /** + * @return whether home is disabled (either by SUW/SysUI/device policy) + */ + public boolean isHomeDisabled() { + return (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) != 0; + } + + /** + * @return whether overview is disabled (either by SUW/SysUI/device policy) + */ + public boolean isOverviewDisabled() { + return (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0; + } + + /** + * Updates the regions for detecting the swipe up/quickswitch and assistant gestures. + */ + public void updateGestureTouchRegions() { + if (!mMode.hasGestures) { + return; + } + + Resources res = mContext.getResources(); + DefaultDisplay.Info displayInfo = mDefaultDisplay.getInfo(); + Point realSize = new Point(displayInfo.realSize); + mSwipeUpTouchRegion.set(0, 0, realSize.x, realSize.y); + if (mMode == NO_BUTTON) { + int touchHeight = ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res); + mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom - touchHeight; + + final int assistantWidth = res.getDimensionPixelSize(R.dimen.gestures_assistant_width); + final float assistantHeight = Math.max(touchHeight, + QuickStepContract.getWindowCornerRadius(res)); + mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeUpTouchRegion.bottom; + mAssistantLeftRegion.top = mAssistantRightRegion.top = + mSwipeUpTouchRegion.bottom - assistantHeight; + + mAssistantLeftRegion.left = 0; + mAssistantLeftRegion.right = assistantWidth; + + mAssistantRightRegion.right = mSwipeUpTouchRegion.right; + mAssistantRightRegion.left = mSwipeUpTouchRegion.right - assistantWidth; + } else { + mAssistantLeftRegion.setEmpty(); + mAssistantRightRegion.setEmpty(); + switch (displayInfo.rotation) { + case Surface.ROTATION_90: + mSwipeUpTouchRegion.left = mSwipeUpTouchRegion.right + - ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res); + break; + case Surface.ROTATION_270: + mSwipeUpTouchRegion.right = mSwipeUpTouchRegion.left + + ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res); + break; + default: + mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom + - ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res); + } + } + } + + /** + * @return whether the coordinates of the {@param event} is in the swipe up gesture region. + */ + public boolean isInSwipeUpTouchRegion(MotionEvent event) { + return mSwipeUpTouchRegion.contains(event.getX(), event.getY()); + } + + /** + * @return whether the coordinates of the {@param event} with the given {@param pointerIndex} + * is in the swipe up gesture region. + */ + public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) { + return mSwipeUpTouchRegion.contains(event.getX(pointerIndex), event.getY(pointerIndex)); + } + + /** + * Sets the region in screen space where the gestures should be deferred (ie. due to specific + * nav bar ui). + */ + public void setDeferredGestureRegion(Region deferredGestureRegion) { + mDeferredGestureRegion.set(deferredGestureRegion); + } + + /** + * @return whether the given {@param event} is in the deferred gesture region indicating that + * the Launcher should not immediately start the recents animation until the gesture + * passes a certain threshold. + */ + public boolean isInDeferredGestureRegion(MotionEvent event) { + return mDeferredGestureRegion.contains((int) event.getX(), (int) event.getY()); + } + + /** + * @return whether the given {@param event} is in the app-requested gesture-exclusion region. + * This is only used for quickswitch, and not swipe up. + */ + public boolean isInExclusionRegion(MotionEvent event) { + // mExclusionRegion can change on binder thread, use a local instance here. + Region exclusionRegion = mExclusionRegion; + return mMode == NO_BUTTON && exclusionRegion != null + && exclusionRegion.contains((int) event.getX(), (int) event.getY()); + } + + /** + * Sets whether the assistant is available. + */ + public void setAssistantAvailable(boolean assistantAvailable) { + mAssistantAvailable = assistantAvailable; + } + + /** + * Sets the visibility fraction of the assistant. + */ + public void setAssistantVisibility(float visibility) { + mAssistantVisibility = visibility; + } + + /** + * @return the visibility fraction of the assistant. + */ + public float getAssistantVisibility() { + return mAssistantVisibility; + } + + /** + * @param ev An ACTION_DOWN motion event + * @return whether the given motion event can trigger the assistant. + */ + public boolean canTriggerAssistantAction(MotionEvent ev) { + return mAssistantAvailable + && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags) + && (mAssistantLeftRegion.contains(ev.getX(), ev.getY()) + || mAssistantRightRegion.contains(ev.getX(), ev.getY())) + && !isLockToAppActive(); + } + + public void dump(PrintWriter pw) { + pw.println("DeviceState:"); + pw.println(" canStartSystemGesture=" + canStartSystemGesture()); + pw.println(" systemUiFlags=" + mSystemUiStateFlags); + pw.println(" systemUiFlagsDesc=" + + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags)); + pw.println(" assistantAvailable=" + mAssistantAvailable); + pw.println(" assistantDisabled=" + + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)); + } +} From 4b5c1ef71b0b3bf0577b8c431f1d3b1c459cb8c9 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 19 Sep 2019 18:26:47 -0700 Subject: [PATCH 089/109] Adding support for intentionally leaking views. Bug: 139137636 Change-Id: I923d1781daee9ae47eb306ee8fa3c44790c6993f --- .../android/launcher3/testing/TestInformationHandler.java | 8 ++++++++ src/com/android/launcher3/testing/TestProtocol.java | 1 + .../android/launcher3/tapl/LauncherInstrumentation.java | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index f9b2d5fe8f..fa9cc3ad61 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -24,6 +24,7 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.os.Bundle; import android.os.Debug; +import android.view.View; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; @@ -167,6 +168,13 @@ public class TestInformationHandler implements ResourceBasedOverride { mLeaks.add(bitmap); break; } + + case TestProtocol.REQUEST_VIEW_LEAK: { + if (mLeaks == null) mLeaks = new LinkedList(); + + mLeaks.add(new View(mContext)); + break; + } } return response; } diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index ac080c2694..add45650c1 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -74,6 +74,7 @@ public final class TestProtocol { public static final String REQUEST_TOTAL_PSS_KB = "total_pss"; public static final String REQUEST_JAVA_LEAK = "java-leak"; public static final String REQUEST_NATIVE_LEAK = "native-leak"; + public static final String REQUEST_VIEW_LEAK = "view-leak"; 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 afdabea8be..41a5b49be7 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -1001,4 +1001,8 @@ public final class LauncherInstrumentation { public void produceNativeLeak() { getTestInfo(TestProtocol.REQUEST_NATIVE_LEAK); } + + public void produceViewLeak() { + getTestInfo(TestProtocol.REQUEST_VIEW_LEAK); + } } \ No newline at end of file From e4607587edf141413844d8b7c81fe5cc110e8791 Mon Sep 17 00:00:00 2001 From: Jeff Pierce Date: Thu, 19 Sep 2019 16:17:55 -0700 Subject: [PATCH 090/109] Add feature flag + leftward swipe for Compose access. Stole ag/9453040 from jspierce@ and added a feature flag. ag/9453040: Exploratory prototype to test leftward swipe access to Compose across home screen, launcher, and lock screen. Requires Compose APK (installed separately). Change-Id: I15a045976b1eb41392795d3a4f0743f365dec1d2 --- .../quickstep/TouchInteractionService.java | 9 + .../AssistantInputConsumer.java | 2 +- .../inputconsumers/InputConsumer.java | 2 + .../QuickCaptureTouchConsumer.java | 219 ++++++++++++++++++ res/anim/slide_in_right.xml | 9 + .../launcher3/config/FeatureFlags.java | 2 + 6 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureTouchConsumer.java create mode 100644 res/anim/slide_in_right.xml diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 4ca80556d6..85da0aa488 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -53,6 +53,7 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Utilities; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.EventLogArray; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.AppLaunchTracker; @@ -69,6 +70,7 @@ import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; +import com.android.quickstep.inputconsumers.QuickCaptureTouchConsumer; import com.android.quickstep.inputconsumers.ResetGestureInputConsumer; import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; import com.android.systemui.shared.recents.IOverviewProxy; @@ -454,6 +456,13 @@ public class TouchInteractionService extends Service implements mInputMonitorCompat); } + if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) { + // Put the Compose gesture as higher priority than the Assistant or base gestures + base = new QuickCaptureTouchConsumer(this, base, + mInputMonitorCompat, mOverviewComponentObserver.getActivityControlHelper()); + } + + if (mDeviceState.isScreenPinningActive()) { // Note: we only allow accessibility to wrap this, and it replaces the previous // base input consumer (which should be NO_OP anyway since topTaskLocked == true). diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java index a2a1c43023..7cec924d52 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java @@ -131,8 +131,8 @@ public class AssistantInputConsumer extends DelegateInputConsumer { case ACTION_POINTER_DOWN: { if (mState != STATE_ACTIVE) { mState = STATE_DELEGATE_ACTIVE; - break; } + break; } case ACTION_POINTER_UP: { int ptrIdx = ev.getActionIndex(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java index a1e5d47a53..045bafec03 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java @@ -33,6 +33,7 @@ public interface InputConsumer { int TYPE_SCREEN_PINNED = 1 << 6; int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7; int TYPE_RESET_GESTURE = 1 << 8; + int TYPE_QUICK_CAPTURE = 1 << 9; String[] NAMES = new String[] { "TYPE_NO_OP", // 0 @@ -44,6 +45,7 @@ public interface InputConsumer { "TYPE_SCREEN_PINNED", // 6 "TYPE_OVERVIEW_WITHOUT_FOCUS", // 7 "TYPE_RESET_GESTURE", // 8 + "TYPE_QUICK_CAPTURE", // 9 }; InputConsumer NO_OP = () -> TYPE_NO_OP; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureTouchConsumer.java new file mode 100644 index 0000000000..3101bb8263 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureTouchConsumer.java @@ -0,0 +1,219 @@ +/* + * 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.quickstep.inputconsumers; + +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_MOVE; +import static android.view.MotionEvent.ACTION_POINTER_DOWN; +import static android.view.MotionEvent.ACTION_POINTER_UP; +import static android.view.MotionEvent.ACTION_UP; + +import static com.android.launcher3.Utilities.squaredHypot; + +import android.app.ActivityOptions; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.PointF; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.R; +import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.system.InputMonitorCompat; + +/** + * Touch consumer for handling events to launch quick capture from launcher + * @param Draggable activity subclass used by RecentsView + */ +public class QuickCaptureTouchConsumer + extends DelegateInputConsumer { + + private static final String TAG = "QuickCaptureTouchConsumer"; + + private static final String QUICK_CAPTURE_PACKAGE = "com.google.auxe.compose"; + private static final String QUICK_CAPTURE_PACKAGE_DEV = "com.google.auxe.compose.debug"; + + private static final String EXTRA_DEVICE_STATE = "deviceState"; + private static final String DEVICE_STATE_LOCKED = "Locked"; + private static final String DEVICE_STATE_LAUNCHER = "Launcher"; + private static final String DEVICE_STATE_APP = "App"; + private static final String DEVICE_STATE_UNKNOWN = "Unknown"; + + private static final int ANGLE_THRESHOLD = 35; // Degrees + + private final PointF mDownPos = new PointF(); + private final PointF mLastPos = new PointF(); + private final PointF mStartDragPos = new PointF(); + + private int mActivePointerId = -1; + private boolean mPassedSlop = false; + + private final float mSquaredSlop; + + private Context mContext; + + private RecentsView mRecentsView; + + public QuickCaptureTouchConsumer(Context context, InputConsumer delegate, + InputMonitorCompat inputMonitor, ActivityControlHelper activityControlHelper) { + super(delegate, inputMonitor); + mContext = context; + + float slop = ViewConfiguration.get(context).getScaledTouchSlop(); + mSquaredSlop = slop * slop; + + activityControlHelper.createActivityInitListener(this::onActivityInit).register(); + } + + @Override + public int getType() { + return TYPE_QUICK_CAPTURE | mDelegate.getType(); + } + + private boolean onActivityInit(final T activity, Boolean alreadyOnHome) { + mRecentsView = activity.getOverviewPanel(); + + return true; + } + + @Override + public void onMotionEvent(MotionEvent ev) { + switch (ev.getActionMasked()) { + case ACTION_DOWN: { + mActivePointerId = ev.getPointerId(0); + mDownPos.set(ev.getX(), ev.getY()); + mLastPos.set(mDownPos); + + break; + } + case ACTION_POINTER_DOWN: { + if (mState != STATE_ACTIVE) { + mState = STATE_DELEGATE_ACTIVE; + } + break; + } + case ACTION_POINTER_UP: { + int ptrIdx = ev.getActionIndex(); + int ptrId = ev.getPointerId(ptrIdx); + if (ptrId == mActivePointerId) { + final int newPointerIdx = ptrIdx == 0 ? 1 : 0; + mDownPos.set( + ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x), + ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y)); + mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx)); + mActivePointerId = ev.getPointerId(newPointerIdx); + } + break; + } + case ACTION_MOVE: { + if (mState == STATE_DELEGATE_ACTIVE) { + break; + } + if (!mDelegate.allowInterceptByParent()) { + mState = STATE_DELEGATE_ACTIVE; + break; + } + int pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex == -1) { + break; + } + mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex)); + + if (!mPassedSlop) { + // Normal gesture, ensure we pass the slop before we start tracking the gesture + if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y) + > mSquaredSlop) { + + mPassedSlop = true; + mStartDragPos.set(mLastPos.x, mLastPos.y); + + if (isValidQuickCaptureGesture()) { + setActive(ev); + } else { + mState = STATE_DELEGATE_ACTIVE; + } + } + } + + break; + } + case ACTION_CANCEL: + case ACTION_UP: + if (mState != STATE_DELEGATE_ACTIVE && mPassedSlop) { + startQuickCapture(); + } + + mPassedSlop = false; + mState = STATE_INACTIVE; + break; + } + + if (mState != STATE_ACTIVE) { + mDelegate.onMotionEvent(ev); + } + } + + private boolean isValidQuickCaptureGesture() { + // Make sure there isn't an app to quick switch to on our right + boolean atRightMostApp = (mRecentsView == null || mRecentsView.getRunningTaskIndex() <= 0); + + // Check if the gesture is within our angle threshold of horizontal + float deltaY = Math.abs(mLastPos.y - mDownPos.y); + float deltaX = mDownPos.x - mLastPos.x; // Positive if this is a gesture to the left + boolean angleInBounds = Math.toDegrees(Math.atan2(deltaY, deltaX)) < ANGLE_THRESHOLD; + + return atRightMostApp && angleInBounds; + } + + private void startQuickCapture() { + // Inspect our delegate's type to figure out where the user invoked Compose + String deviceState = DEVICE_STATE_UNKNOWN; + int consumerType = mDelegate.getType(); + if (((consumerType & InputConsumer.TYPE_OVERVIEW) > 0) + || ((consumerType & InputConsumer.TYPE_OVERVIEW_WITHOUT_FOCUS)) > 0) { + deviceState = DEVICE_STATE_LAUNCHER; + } else if ((consumerType & InputConsumer.TYPE_OTHER_ACTIVITY) > 0) { + deviceState = DEVICE_STATE_APP; + } else if (((consumerType & InputConsumer.TYPE_RESET_GESTURE) > 0) + || ((consumerType & InputConsumer.TYPE_DEVICE_LOCKED) > 0)) { + deviceState = DEVICE_STATE_LOCKED; + } + + // Then launch the app + PackageManager pm = mContext.getPackageManager(); + + Intent qcIntent = pm.getLaunchIntentForPackage(QUICK_CAPTURE_PACKAGE); + + if (qcIntent == null) { + // If we couldn't find the regular app, try the dev version + qcIntent = pm.getLaunchIntentForPackage(QUICK_CAPTURE_PACKAGE_DEV); + } + + if (qcIntent != null) { + qcIntent.putExtra(EXTRA_DEVICE_STATE, deviceState); + + Bundle options = ActivityOptions.makeCustomAnimation(mContext, R.anim.slide_in_right, + 0).toBundle(); + + mContext.startActivity(qcIntent, options); + } + } +} diff --git a/res/anim/slide_in_right.xml b/res/anim/slide_in_right.xml new file mode 100644 index 0000000000..55d3e54025 --- /dev/null +++ b/res/anim/slide_in_right.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index c502dd7af1..4abdbefc1b 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -117,6 +117,8 @@ public final class FeatureFlags { public static final TogglableFlag ENABLE_PREDICTION_DISMISS = new TogglableFlag( "ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list"); + public static final TogglableFlag ENABLE_QUICK_CAPTURE_GESTURE = new TogglableFlag( + "ENABLE_QUICK_CAPTURE_GESTURE", false, "Swipe from right to left to quick capture"); public static void initialize(Context context) { // Avoid the disk read for user builds From 629c87283fd8ceedae75f6d51326474526d00879 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 1 Oct 2019 12:59:11 -0700 Subject: [PATCH 091/109] 3/ Move touch interaction log to its own class Bug: 141886704 Change-Id: I5f27faf83ccacc2d2eb2914f15e860d07628c37c --- .../android/quickstep/BaseSwipeUpHandler.java | 4 +- .../quickstep/TouchInteractionService.java | 23 +++-------- .../WindowTransformSwipeHandler.java | 12 +++--- .../DeviceLockedInputConsumer.java | 2 +- .../OtherActivityInputConsumer.java | 8 ++-- .../inputconsumers/OverviewInputConsumer.java | 4 +- .../OverviewWithoutFocusInputConsumer.java | 4 +- .../quickstep/util/ActiveGestureLog.java | 39 +++++++++++++++++++ 8 files changed, 62 insertions(+), 34 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index 770857ba43..5d7d2ff6d8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -25,7 +25,6 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; -import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import android.animation.Animator; import android.annotation.TargetApi; @@ -60,6 +59,7 @@ import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.InputConsumer; +import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; @@ -253,7 +253,7 @@ public abstract class BaseSwipeUpHandler { public class TouchInteractionService extends Service implements NavigationModeChangeListener { - /** - * NOTE: This value should be kept same as - * ActivityTaskManagerService#INTENT_EXTRA_LOG_TRACE_ID in platform - */ - public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID"; - - - public static final EventLogArray TOUCH_INTERACTION_LOG = - new EventLogArray("touch_interaction_log", 40); - private static final String TAG = "TouchInteractionService"; private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount"; @@ -403,14 +393,14 @@ public class TouchInteractionService extends Service implements MotionEvent event = (MotionEvent) ev; if (event.getAction() == ACTION_DOWN) { - mLogId = TOUCH_INTERACTION_LOG.generateAndSetLogId(); + mLogId = ActiveGestureLog.INSTANCE.generateAndSetLogId(); sSwipeSharedState.setLogTraceId(mLogId); if (mDeviceState.isInSwipeUpTouchRegion(event)) { boolean useSharedState = mConsumer.useSharedSwipeState(); mConsumer.onConsumerAboutToBeSwitched(); mConsumer = newConsumer(useSharedState, event); - TOUCH_INTERACTION_LOG.addLog("setInputConsumer", mConsumer.getType()); + ActiveGestureLog.INSTANCE.addLog("setInputConsumer", mConsumer.getType()); mUncheckedConsumer = mConsumer; } else if (mDeviceState.isUserUnlocked() && mMode == Mode.NO_BUTTON && mDeviceState.canTriggerAssistantAction(event)) { @@ -426,7 +416,7 @@ public class TouchInteractionService extends Service implements } } - TOUCH_INTERACTION_LOG.addLog("onMotionEvent", event.getActionMasked()); + ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked()); mUncheckedConsumer.onMotionEvent(event); DejankBinderTracker.disallowBinderTrackingInTests(); } @@ -683,8 +673,7 @@ public class TouchInteractionService extends Service implements pw.println(" ENABLE_QUICKSTEP_LIVE_TILE=" + ENABLE_QUICKSTEP_LIVE_TILE.get()); pw.println(" ENABLE_HINTS_IN_OVERVIEW=" + ENABLE_HINTS_IN_OVERVIEW.get()); pw.println(" FAKE_LANDSCAPE_UI=" + FAKE_LANDSCAPE_UI.get()); - TOUCH_INTERACTION_LOG.dump("", pw); - + ActiveGestureLog.INSTANCE.dump("", pw); } } @@ -696,7 +685,7 @@ public class TouchInteractionService extends Service implements private void onCommand(PrintWriter pw, ArgList args) { switch (args.nextArg()) { case "clear-touch-log": - TOUCH_INTERACTION_LOG.clear(); + ActiveGestureLog.INSTANCE.clear(); break; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 5cf987ad6c..b0628e55df 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -29,7 +29,6 @@ import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.HIDE; import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.PEEK; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; -import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.HOME; import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.LAST_TASK; import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK; @@ -78,6 +77,7 @@ import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; +import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.RecentsAnimationTargets; @@ -609,7 +609,7 @@ public class WindowTransformSwipeHandler @Override public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { super.onRecentsAnimationStart(targetSet); - TOUCH_INTERACTION_LOG.addLog("startRecentsAnimationCallback", targetSet.apps.length); + ActiveGestureLog.INSTANCE.addLog("startRecentsAnimationCallback", targetSet.apps.length); setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); mPassedOverviewThreshold = false; @@ -620,7 +620,7 @@ public class WindowTransformSwipeHandler mRecentsAnimationWrapper.setController(null); mActivityInitListener.unregister(); setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); - TOUCH_INTERACTION_LOG.addLog("cancelRecentsAnimation"); + ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation"); } @Override @@ -1019,7 +1019,7 @@ public class WindowTransformSwipeHandler @UiThread private void resumeLastTask() { mRecentsAnimationWrapper.finish(false /* toRecents */, null); - TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false); + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); doLogGesture(LAST_TASK); reset(); } @@ -1164,7 +1164,7 @@ public class WindowTransformSwipeHandler () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } } - TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true); + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true); } private void finishCurrentTransitionToHome() { @@ -1173,7 +1173,7 @@ public class WindowTransformSwipeHandler () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED), true /* sendUserLeaveHint */); } - TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true); + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true); doLogGesture(HOME); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index ba2d6d133c..25b4fe4f15 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -22,9 +22,9 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; -import static com.android.quickstep.TouchInteractionService.INTENT_EXTRA_LOG_TRACE_ID; import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; +import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; import android.content.ComponentName; import android.content.Context; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 6776e84d27..3e66d7b1a4 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -27,9 +27,8 @@ import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.util.RaceConditionTracker.ENTER; import static com.android.launcher3.util.RaceConditionTracker.EXIT; -import static com.android.quickstep.TouchInteractionService.INTENT_EXTRA_LOG_TRACE_ID; -import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; +import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import android.annotation.TargetApi; @@ -58,6 +57,7 @@ import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; +import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; @@ -311,7 +311,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } private void notifyGestureStarted() { - TOUCH_INTERACTION_LOG.addLog("startQuickstep"); + ActiveGestureLog.INSTANCE.addLog("startQuickstep"); if (mInteractionHandler == null) { return; } @@ -327,7 +327,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private void startTouchTrackingForWindowAnimation( long touchTimeMs, boolean isLikelyToStartNewTask) { - TOUCH_INTERACTION_LOG.addLog("startRecentsAnimation"); + ActiveGestureLog.INSTANCE.addLog("startRecentsAnimation"); RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener(); final BaseSwipeUpHandler handler = mHandlerFactory.newHandler(mRunningTask, touchTimeMs, diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index 4857d00260..74e457c686 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -16,7 +16,6 @@ package com.android.quickstep.inputconsumers; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; -import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import android.view.KeyEvent; @@ -28,6 +27,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Utilities; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; @@ -102,7 +102,7 @@ public class OverviewInputConsumer mActivityControlHelper.closeOverlay(); ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); - TOUCH_INTERACTION_LOG.addLog("startQuickstep"); + ActiveGestureLog.INSTANCE.addLog("startQuickstep"); } if (mInputMonitor != null) { mInputMonitor.pilferPointers(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java index e11d492331..03e0ae77e5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -21,7 +21,6 @@ import static android.view.MotionEvent.ACTION_MOVE; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Utilities.squaredHypot; -import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import android.content.Context; @@ -37,6 +36,7 @@ import com.android.launcher3.logging.StatsLogUtils; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.NavBarPosition; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; @@ -151,7 +151,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { mActivityControlHelper.closeOverlay(); ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); - TOUCH_INTERACTION_LOG.addLog("startQuickstep"); + ActiveGestureLog.INSTANCE.addLog("startQuickstep"); BaseActivity activity = BaseDraggingActivity.fromContext(mContext); int pageIndex = -1; // This number doesn't reflect workspace page index. // It only indicates that launcher client screen was shown. diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java new file mode 100644 index 0000000000..9a3bb760f1 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java @@ -0,0 +1,39 @@ +/* + * 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.quickstep.util; + +import android.content.Context; + +import com.android.launcher3.logging.EventLogArray; +import com.android.launcher3.util.MainThreadInitializedObject; + +/** + * A log to keep track of the active gesture. + */ +public class ActiveGestureLog extends EventLogArray { + + public static final ActiveGestureLog INSTANCE = new ActiveGestureLog(); + + /** + * NOTE: This value should be kept same as + * ActivityTaskManagerService#INTENT_EXTRA_LOG_TRACE_ID in platform + */ + public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID"; + + public ActiveGestureLog() { + super("touch_interaction_log", 40); + } +} From 8ff53f7e65fb776da729500cc7b82ec37ea8f843 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 1 Oct 2019 14:10:37 -0700 Subject: [PATCH 092/109] 4/ Move SystemUiProxy to its own singleton instead of routing through the model Bug: 141886704 Change-Id: I415b9ef7b57b525407e3a341b946e3ca66125102 --- .../quickstep/TouchInteractionService.java | 5 +- .../uioverrides/RecentsUiFactory.java | 32 +-- .../android/quickstep/TaskSystemShortcut.java | 21 +- .../quickstep/TouchInteractionService.java | 50 ++-- .../AccessibilityInputConsumer.java | 34 +-- .../AssistantInputConsumer.java | 70 ++--- .../ScreenPinnedInputConsumer.java | 25 +- .../util/AppWindowAnimationHelper.java | 16 +- .../StatusBarTouchController.java | 26 +- .../quickstep/OverviewInteractionState.java | 21 +- .../com/android/quickstep/RecentsModel.java | 24 +- .../com/android/quickstep/SystemUiProxy.java | 262 ++++++++++++++++++ .../launcher3/util/UiThreadHelper.java | 14 +- 13 files changed, 371 insertions(+), 229 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/SystemUiProxy.java diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java index 6b936cbfc0..0012ad4e98 100644 --- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -36,6 +36,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; @@ -56,7 +57,7 @@ public class TouchInteractionService extends Service { public void onInitialize(Bundle bundle) throws RemoteException { ISystemUiProxy iSystemUiProxy = ISystemUiProxy.Stub .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); - mRecentsModel.setSystemUiProxy(iSystemUiProxy); + SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(iSystemUiProxy); } @Override @@ -120,7 +121,7 @@ public class TouchInteractionService extends Service { public void onMotionEvent(MotionEvent ev) { } public void onBind(ISystemUiProxy iSystemUiProxy) { - mRecentsModel.setSystemUiProxy(iSystemUiProxy); + SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(iSystemUiProxy); } }; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index 2f8af44663..b8e9137fbc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -23,8 +23,6 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Context; import android.graphics.Rect; -import android.os.RemoteException; -import android.util.Log; import android.view.Gravity; import com.android.launcher3.DeviceProfile; @@ -45,13 +43,11 @@ import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchT import com.android.launcher3.util.TouchController; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper.AsyncCommand; -import com.android.quickstep.RecentsModel; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.TouchInteractionService; -import com.android.quickstep.util.SharedApiCompat; +import com.android.quickstep.SystemUiProxy; import com.android.quickstep.views.RecentsView; -import com.android.systemui.shared.recents.ISystemUiProxy; import java.util.ArrayList; @@ -60,21 +56,16 @@ import java.util.ArrayList; */ public abstract class RecentsUiFactory { - public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false; - private static final String TAG = RecentsUiFactory.class.getSimpleName(); - private static AsyncCommand newSetShelfHeightCmd(Context context) { - return (visible, height) -> { - ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(context).getSystemUiProxy(); - if (sysUiProxy == null) return; - try { - SharedApiCompat.setShelfHeight(sysUiProxy, visible != 0, height); - } catch (RemoteException e) { - Log.e(TAG, "Error setShelfHeight", e); - } - }; - } + public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false; + + /** + * Reusable command for applying the shelf height on the background thread. + */ + public static final AsyncCommand SET_SHELF_HEIGHT = (context, visible, height) -> { + SystemUiProxy.INSTANCE.get(context).setShelfHeight(visible, (int) height); + }; public static RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) { @Override @@ -218,9 +209,8 @@ public abstract class RecentsUiFactory { DeviceProfile profile = launcher.getDeviceProfile(); boolean visible = (state == NORMAL || state == OVERVIEW) && launcher.isUserActive() && !profile.isVerticalBarLayout(); - UiThreadHelper.runAsyncCommand(launcher, newSetShelfHeightCmd(launcher), - visible ? 1 : 0, profile.hotseatBarSizePx); - + UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT, visible, + profile.hotseatBarSizePx); if (state == NORMAL) { launcher.getOverviewPanel().setSwipeDownShouldLaunchApp(false); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java index 1af0db07d8..5a2e3ff821 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java @@ -28,9 +28,7 @@ import android.graphics.Color; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; -import android.os.RemoteException; import android.os.UserHandle; -import android.util.Log; import android.view.View; import com.android.launcher3.BaseDraggingActivity; @@ -44,7 +42,6 @@ import com.android.launcher3.util.InstantAppResolver; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; @@ -240,13 +237,7 @@ public class TaskSystemShortcut extends SystemShortcut @Override protected boolean onActivityStarted(BaseDraggingActivity activity) { - ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy(); - try { - sysUiProxy.onSplitScreenInvoked(); - } catch (RemoteException e) { - Log.w(TAG, "Failed to notify SysUI of split screen: ", e); - return false; - } + SystemUiProxy.INSTANCE.get(activity).onSplitScreenInvoked(); activity.getUserEventDispatcher().logActionOnControl(TAP, LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET); return true; @@ -293,8 +284,7 @@ public class TaskSystemShortcut extends SystemShortcut @Override public View.OnClickListener getOnClickListener( BaseDraggingActivity activity, TaskView taskView) { - ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy(); - if (sysUiProxy == null) { + if (!SystemUiProxy.INSTANCE.get(activity).isActive()) { return null; } if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { @@ -307,11 +297,8 @@ public class TaskSystemShortcut extends SystemShortcut return view -> { Consumer resultCallback = success -> { if (success) { - try { - sysUiProxy.startScreenPinning(taskView.getTask().key.id); - } catch (RemoteException e) { - Log.w(TAG, "Failed to start screen pinning: ", e); - } + SystemUiProxy.INSTANCE.get(activity).startScreenPinning( + taskView.getTask().key.id); } else { taskView.notifyTaskLaunchFailed(TAG); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 708408a863..d1c63819ac 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -42,7 +42,6 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Looper; -import android.os.RemoteException; import android.util.Log; import android.view.Choreographer; import android.view.InputEvent; @@ -122,10 +121,11 @@ public class TouchInteractionService extends Service implements private final IBinder mMyBinder = new IOverviewProxy.Stub() { public void onInitialize(Bundle bundle) { - mISystemUiProxy = ISystemUiProxy.Stub - .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); + ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface( + bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); + MAIN_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(TouchInteractionService.this) + .setProxy(proxy)); MAIN_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor); - MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiProxySet); MAIN_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */)); sIsInitialized = true; } @@ -235,7 +235,6 @@ public class TouchInteractionService extends Service implements private ActivityManagerWrapper mAM; private RecentsModel mRecentsModel; - private ISystemUiProxy mISystemUiProxy; private OverviewCommandHelper mOverviewCommandHelper; private OverviewComponentObserver mOverviewComponentObserver; private OverviewInteractionState mOverviewInteractionState; @@ -284,24 +283,20 @@ public class TouchInteractionService extends Service implements Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 1"); } disposeEventHandlers(); - if (!mMode.hasGestures || mISystemUiProxy == null) { + if (!mMode.hasGestures || !SystemUiProxy.INSTANCE.get(this).isActive()) { return; } if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 2"); } - try { - mInputMonitorCompat = InputMonitorCompat.fromBundle(mISystemUiProxy - .monitorGestureInput("swipe-up", mDeviceState.getDisplayId()), - KEY_EXTRA_INPUT_MONITOR); - mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(), - mMainChoreographer, this::onInputEvent); - if (TestProtocol.sDebugTracing) { - Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 3"); - } - } catch (RemoteException e) { - Log.e(TAG, "Unable to create input monitor", e); + Bundle bundle = SystemUiProxy.INSTANCE.get(this).monitorGestureInput("swipe-up", + mDeviceState.getDisplayId()); + mInputMonitorCompat = InputMonitorCompat.fromBundle(bundle, KEY_EXTRA_INPUT_MONITOR); + mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(), + mMainChoreographer, this::onInputEvent); + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_BACKGROUND_TO_OVERVIEW_TAG, "initInputMonitor 3"); } mDeviceState.updateGestureTouchRegions(); @@ -326,7 +321,6 @@ public class TouchInteractionService extends Service implements sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver); mInputConsumer.registerInputConsumer(); - onSystemUiProxySet(); onSystemUiFlagsChanged(); onAssistantVisibilityChanged(); @@ -336,14 +330,6 @@ public class TouchInteractionService extends Service implements .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT)); } - @UiThread - private void onSystemUiProxySet() { - if (mDeviceState.isUserUnlocked()) { - mRecentsModel.setSystemUiProxy(mISystemUiProxy); - mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy); - } - } - @UiThread private void onSystemUiFlagsChanged() { if (mDeviceState.isUserUnlocked()) { @@ -368,8 +354,9 @@ public class TouchInteractionService extends Service implements mOverviewComponentObserver.onDestroy(); } disposeEventHandlers(); - SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this); mDeviceState.destroy(); + SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this); + SystemUiProxy.INSTANCE.get(this).setProxy(null); sConnected = false; super.onDestroy(); @@ -408,7 +395,7 @@ public class TouchInteractionService extends Service implements // not interrupt it. QuickSwitch assumes that interruption can only happen if the // next gesture is also quick switch. mUncheckedConsumer = - new AssistantInputConsumer(this, mISystemUiProxy, + new AssistantInputConsumer(this, mOverviewComponentObserver.getActivityControlHelper(), InputConsumer.NO_OP, mInputMonitorCompat); } else { @@ -442,8 +429,7 @@ public class TouchInteractionService extends Service implements final ActivityControlHelper activityControl = mOverviewComponentObserver.getActivityControlHelper(); if (mDeviceState.canTriggerAssistantAction(event)) { - base = new AssistantInputConsumer(this, mISystemUiProxy, activityControl, base, - mInputMonitorCompat); + base = new AssistantInputConsumer(this, activityControl, base, mInputMonitorCompat); } if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) { @@ -456,11 +442,11 @@ public class TouchInteractionService extends Service implements if (mDeviceState.isScreenPinningActive()) { // Note: we only allow accessibility to wrap this, and it replaces the previous // base input consumer (which should be NO_OP anyway since topTaskLocked == true). - base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl); + base = new ScreenPinnedInputConsumer(this, activityControl); } if (mDeviceState.isAccessibilityMenuAvailable()) { - base = new AccessibilityInputConsumer(this, mDeviceState, mISystemUiProxy, base, + base = new AccessibilityInputConsumer(this, mDeviceState, base, mInputMonitorCompat); } } else { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java index 92bcfb5fda..f9bbd37abb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java @@ -23,8 +23,6 @@ import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import android.content.Context; -import android.os.RemoteException; -import android.util.Log; import android.view.Display; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -33,7 +31,7 @@ import android.view.ViewConfiguration; import com.android.launcher3.R; import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.util.MotionPauseDetector; -import com.android.systemui.shared.recents.ISystemUiProxy; +import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.InputMonitorCompat; /** @@ -43,7 +41,7 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { private static final String TAG = "A11yInputConsumer"; - private final ISystemUiProxy mSystemUiProxy; + private final Context mContext; private final VelocityTracker mVelocityTracker; private final MotionPauseDetector mMotionPauseDetector; private final RecentsAnimationDeviceState mDeviceState; @@ -56,9 +54,9 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { private float mTotalY; public AccessibilityInputConsumer(Context context, RecentsAnimationDeviceState deviceState, - ISystemUiProxy systemUiProxy, InputConsumer delegate, InputMonitorCompat inputMonitor) { + InputConsumer delegate, InputMonitorCompat inputMonitor) { super(delegate, inputMonitor); - mSystemUiProxy = systemUiProxy; + mContext = context; mVelocityTracker = VelocityTracker.obtain(); mMinGestureDistance = context.getResources() .getDimension(R.dimen.accessibility_gesture_min_swipe_distance); @@ -126,22 +124,18 @@ public class AccessibilityInputConsumer extends DelegateInputConsumer { } case ACTION_UP: if (mState == STATE_ACTIVE) { - try { - if (mDeviceState.isAccessibilityMenuShortcutAvailable() - && mMotionPauseDetector.isPaused()) { - mSystemUiProxy.notifyAccessibilityButtonLongClicked(); - } else { - mTotalY += (ev.getY() - mDownY); - mVelocityTracker.computeCurrentVelocity(1000); + if (mDeviceState.isAccessibilityMenuShortcutAvailable() + && mMotionPauseDetector.isPaused()) { + SystemUiProxy.INSTANCE.get(mContext).notifyAccessibilityButtonLongClicked(); + } else { + mTotalY += (ev.getY() - mDownY); + mVelocityTracker.computeCurrentVelocity(1000); - if ((-mTotalY) > mMinGestureDistance - || (-mVelocityTracker.getYVelocity()) > mMinFlingVelocity) { - mSystemUiProxy.notifyAccessibilityButtonClicked( - Display.DEFAULT_DISPLAY); - } + if ((-mTotalY) > mMinGestureDistance + || (-mVelocityTracker.getYVelocity()) > mMinFlingVelocity) { + SystemUiProxy.INSTANCE.get(mContext).notifyAccessibilityButtonClicked( + Display.DEFAULT_DISPLAY); } - } catch (RemoteException e) { - Log.e(TAG, "Unable to notify accessibility event", e); } } // Follow through diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java index 7cec924d52..7cc29e4cc3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java @@ -37,9 +37,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; import android.os.Bundle; -import android.os.RemoteException; import android.os.SystemClock; -import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.HapticFeedbackConstants; @@ -51,7 +49,7 @@ import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; import com.android.quickstep.ActivityControlHelper; -import com.android.systemui.shared.recents.ISystemUiProxy; +import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.InputMonitorCompat; /** @@ -88,17 +86,14 @@ public class AssistantInputConsumer extends DelegateInputConsumer { private final long mTimeThreshold; private final int mAngleThreshold; private final float mSquaredSlop; - private final ISystemUiProxy mSysUiProxy; private final Context mContext; private final GestureDetector mGestureDetector; - public AssistantInputConsumer(Context context, ISystemUiProxy systemUiProxy, - ActivityControlHelper activityControlHelper, InputConsumer delegate, - InputMonitorCompat inputMonitor) { + public AssistantInputConsumer(Context context, ActivityControlHelper activityControlHelper, + InputConsumer delegate, InputMonitorCompat inputMonitor) { super(delegate, inputMonitor); final Resources res = context.getResources(); mContext = context; - mSysUiProxy = systemUiProxy; mDragDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold); mFlingDistThreshold = res.getDimension(R.dimen.gestures_assistant_fling_threshold); mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold); @@ -198,13 +193,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { SWIPE_NOOP, mDirection, NAVBAR); animator.addUpdateListener(valueAnimator -> { float progress = (float) valueAnimator.getAnimatedValue(); - try { - - mSysUiProxy.onAssistantProgress(progress); - } catch (RemoteException e) { - Log.w(TAG, "Failed to send SysUI start/send assistant progress: " - + progress, e); - } + SystemUiProxy.INSTANCE.get(mContext).onAssistantProgress(progress); }); animator.setInterpolator(Interpolators.DEACCEL_2); animator.start(); @@ -224,22 +213,17 @@ public class AssistantInputConsumer extends DelegateInputConsumer { private void updateAssistantProgress() { if (!mLaunchedAssistant) { mLastProgress = Math.min(mDistance * 1f / mDragDistThreshold, 1) * mTimeFraction; - try { - if (mDistance >= mDragDistThreshold && mTimeFraction >= 1) { - mSysUiProxy.onAssistantGestureCompletion(0); - startAssistantInternal(SWIPE); + if (mDistance >= mDragDistThreshold && mTimeFraction >= 1) { + SystemUiProxy.INSTANCE.get(mContext).onAssistantGestureCompletion(0); + startAssistantInternal(SWIPE); - Bundle args = new Bundle(); - args.putInt(OPA_BUNDLE_TRIGGER, OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE); - args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE); - mSysUiProxy.startAssistant(args); - mLaunchedAssistant = true; - } else { - mSysUiProxy.onAssistantProgress(mLastProgress); - } - } catch (RemoteException e) { - Log.w(TAG, "Failed to send SysUI start/send assistant progress: " + mLastProgress, - e); + Bundle args = new Bundle(); + args.putInt(OPA_BUNDLE_TRIGGER, OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE); + args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE); + SystemUiProxy.INSTANCE.get(mContext).startAssistant(args); + mLaunchedAssistant = true; + } else { + SystemUiProxy.INSTANCE.get(mContext).onAssistantProgress(mLastProgress); } } } @@ -274,24 +258,18 @@ public class AssistantInputConsumer extends DelegateInputConsumer { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (isValidAssistantGestureAngle(velocityX, -velocityY) - && mDistance >= mFlingDistThreshold - && !mLaunchedAssistant - && mState != STATE_DELEGATE_ACTIVE) { + && mDistance >= mFlingDistThreshold + && !mLaunchedAssistant + && mState != STATE_DELEGATE_ACTIVE) { mLastProgress = 1; - try { - mSysUiProxy.onAssistantGestureCompletion( - (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY)); - startAssistantInternal(FLING); + SystemUiProxy.INSTANCE.get(mContext).onAssistantGestureCompletion( + (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY)); + startAssistantInternal(FLING); - Bundle args = new Bundle(); - args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE); - mSysUiProxy.startAssistant(args); - mLaunchedAssistant = true; - } catch (RemoteException e) { - Log.w(TAG, - "Failed to send SysUI start/send assistant progress: " + mLastProgress, - e); - } + Bundle args = new Bundle(); + args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_GESTURE); + SystemUiProxy.INSTANCE.get(mContext).startAssistant(args); + mLaunchedAssistant = true; } return true; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java index a0e20f2cd8..cfd9d91428 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java @@ -16,8 +16,6 @@ package com.android.quickstep.inputconsumers; import android.content.Context; -import android.os.RemoteException; -import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; @@ -25,7 +23,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.quickstep.ActivityControlHelper; import com.android.quickstep.util.MotionPauseDetector; -import com.android.systemui.shared.recents.ISystemUiProxy; +import com.android.quickstep.SystemUiProxy; /** * An input consumer that detects swipe up and hold to exit screen pinning mode. @@ -39,25 +37,20 @@ public class ScreenPinnedInputConsumer implements InputConsumer { private float mTouchDownY; - public ScreenPinnedInputConsumer(Context context, ISystemUiProxy sysuiProxy, - ActivityControlHelper activityControl) { + public ScreenPinnedInputConsumer(Context context, ActivityControlHelper activityControl) { mMotionPauseMinDisplacement = context.getResources().getDimension( R.dimen.motion_pause_detector_min_displacement_from_app); mMotionPauseDetector = new MotionPauseDetector(context, true /* makePauseHarderToTrigger*/); mMotionPauseDetector.setOnMotionPauseListener(isPaused -> { if (isPaused) { - try { - sysuiProxy.stopScreenPinning(); - BaseDraggingActivity launcherActivity = activityControl.getCreatedActivity(); - if (launcherActivity != null) { - launcherActivity.getRootView().performHapticFeedback( - HapticFeedbackConstants.LONG_PRESS, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - } - mMotionPauseDetector.clear(); - } catch (RemoteException e) { - Log.e(TAG, "Unable to stop screen pinning ", e); + SystemUiProxy.INSTANCE.get(context).stopScreenPinning(); + BaseDraggingActivity launcherActivity = activityControl.getCreatedActivity(); + if (launcherActivity != null) { + launcherActivity.getRootView().performHapticFeedback( + HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } + mMotionPauseDetector.clear(); } }); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java index dddfc8da34..c03580917c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java @@ -28,7 +28,6 @@ import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; -import android.os.RemoteException; import androidx.annotation.Nullable; @@ -36,13 +35,12 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherState; import com.android.launcher3.R; +import com.android.quickstep.SystemUiProxy; import com.android.launcher3.Utilities; import com.android.launcher3.views.BaseDragLayer; -import com.android.quickstep.RecentsModel; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.utilities.RectFEvaluator; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; @@ -337,14 +335,10 @@ public class AppWindowAnimationHelper { } private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) { - ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy(); - if (sysUiProxy != null) { - try { - mSourceStackBounds.set(sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds()); - return; - } catch (RemoteException e) { - // Use half screen size - } + SystemUiProxy proxy = SystemUiProxy.INSTANCE.get(activity); + if (proxy.isActive()) { + mSourceStackBounds.set(proxy.getNonMinimizedSplitScreenSecondaryBounds()); + return; } // Assume that the task size is half screen size (minus the insets and the divider size) diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java index 11a804356d..16bd9ed384 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java @@ -21,8 +21,6 @@ import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.ACTION_CANCEL; import android.graphics.PointF; -import android.os.RemoteException; -import android.util.Log; import android.util.SparseArray; import android.view.MotionEvent; import android.view.ViewConfiguration; @@ -37,9 +35,8 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.TouchController; -import com.android.quickstep.RecentsModel; -import com.android.systemui.shared.recents.ISystemUiProxy; +import com.android.quickstep.SystemUiProxy; import java.io.PrintWriter; /** @@ -62,9 +59,9 @@ public class StatusBarTouchController implements TouchController { */ private static final int FLAG_SLIPPERY = 0x20000000; - protected final Launcher mLauncher; + private final Launcher mLauncher; + private final SystemUiProxy mSystemUiProxy; private final float mTouchSlop; - private ISystemUiProxy mSysUiProxy; private int mLastAction; private final SparseArray mDownEvents; @@ -73,6 +70,7 @@ public class StatusBarTouchController implements TouchController { public StatusBarTouchController(Launcher l) { mLauncher = l; + mSystemUiProxy = SystemUiProxy.INSTANCE.get(mLauncher); // Guard against TAPs by increasing the touch slop. mTouchSlop = 2 * ViewConfiguration.get(l).getScaledTouchSlop(); mDownEvents = new SparseArray<>(); @@ -82,17 +80,14 @@ public class StatusBarTouchController implements TouchController { public void dump(String prefix, PrintWriter writer) { writer.println(prefix + "mCanIntercept:" + mCanIntercept); writer.println(prefix + "mLastAction:" + MotionEvent.actionToString(mLastAction)); - writer.println(prefix + "mSysUiProxy available:" + (mSysUiProxy != null)); + writer.println(prefix + "mSysUiProxy available:" + + SystemUiProxy.INSTANCE.get(mLauncher).isActive()); } private void dispatchTouchEvent(MotionEvent ev) { - try { - if (mSysUiProxy != null) { - mLastAction = ev.getActionMasked(); - mSysUiProxy.onStatusBarMotionEvent(ev); - } - } catch (RemoteException e) { - Log.e(TAG, "Remote exception on sysUiProxy.", e); + if (mSystemUiProxy.isActive()) { + mLastAction = ev.getActionMasked(); + mSystemUiProxy.onStatusBarMotionEvent(ev); } } @@ -170,7 +165,6 @@ public class StatusBarTouchController implements TouchController { return false; } } - mSysUiProxy = RecentsModel.INSTANCE.get(mLauncher).getSystemUiProxy(); - return mSysUiProxy != null; + return SystemUiProxy.INSTANCE.get(mLauncher).isActive(); } } \ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java index 17462ab6b3..6b68b1952a 100644 --- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java +++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java @@ -20,15 +20,12 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.content.Context; import android.os.Handler; import android.os.Message; -import android.os.RemoteException; -import android.util.Log; import androidx.annotation.WorkerThread; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.util.MainThreadInitializedObject; -import com.android.systemui.shared.recents.ISystemUiProxy; /** * Sets alpha for the back button @@ -43,7 +40,6 @@ public class OverviewInteractionState { public static final MainThreadInitializedObject INSTANCE = new MainThreadInitializedObject<>(OverviewInteractionState::new); - private static final int MSG_SET_PROXY = 200; private static final int MSG_SET_BACK_BUTTON_ALPHA = 201; private final Context mContext; @@ -51,7 +47,6 @@ public class OverviewInteractionState { private final Handler mBgHandler; // These are updated on the background thread - private ISystemUiProxy mISystemUiProxy; private float mBackButtonAlpha = 1; private int mSystemUiStateFlags; @@ -82,10 +77,6 @@ public class OverviewInteractionState { .sendToTarget(); } - public void setSystemUiProxy(ISystemUiProxy proxy) { - mBgHandler.obtainMessage(MSG_SET_PROXY, proxy).sendToTarget(); - } - // TODO(141886704): See if we can remove this public void setSystemUiStateFlags(int stateFlags) { mSystemUiStateFlags = stateFlags; @@ -105,9 +96,6 @@ public class OverviewInteractionState { private boolean handleBgMessage(Message msg) { switch (msg.what) { - case MSG_SET_PROXY: - mISystemUiProxy = (ISystemUiProxy) msg.obj; - break; case MSG_SET_BACK_BUTTON_ALPHA: applyBackButtonAlpha((float) msg.obj, msg.arg1 == 1); return true; @@ -117,14 +105,7 @@ public class OverviewInteractionState { @WorkerThread private void applyBackButtonAlpha(float alpha, boolean animate) { - if (mISystemUiProxy == null) { - return; - } - try { - mISystemUiProxy.setBackButtonAlpha(alpha, animate); - } catch (RemoteException e) { - Log.w(TAG, "Unable to update overview back button alpha", e); - } + SystemUiProxy.INSTANCE.get(mContext).setBackButtonAlpha(alpha, animate); } private void onNavigationModeChanged(SysUINavigationMode.Mode mode) { diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index e86a1c100e..465d4648e6 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -29,12 +29,9 @@ import android.content.pm.LauncherApps; import android.os.Build; import android.os.Looper; import android.os.Process; -import android.os.RemoteException; import android.os.UserHandle; -import android.util.Log; import com.android.launcher3.util.MainThreadInitializedObject; -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; @@ -60,8 +57,6 @@ public class RecentsModel extends TaskStackChangeListener { private final List mThumbnailChangeListeners = new ArrayList<>(); private final Context mContext; - private ISystemUiProxy mSystemUiProxy; - private final RecentTasksList mTaskList; private final TaskIconCache mIconCache; private final TaskThumbnailCache mThumbnailCache; @@ -177,14 +172,6 @@ public class RecentsModel extends TaskStackChangeListener { mIconCache.onTaskRemoved(dummyKey); } - public void setSystemUiProxy(ISystemUiProxy systemUiProxy) { - mSystemUiProxy = systemUiProxy; - } - - public ISystemUiProxy getSystemUiProxy() { - return mSystemUiProxy; - } - public void onTrimMemory(int level) { if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { mThumbnailCache.getHighResLoadingState().setVisible(false); @@ -197,16 +184,7 @@ public class RecentsModel extends TaskStackChangeListener { } public void onOverviewShown(boolean fromHome, String tag) { - if (mSystemUiProxy == null) { - return; - } - try { - mSystemUiProxy.onOverviewShown(fromHome); - } catch (RemoteException e) { - Log.w(tag, - "Failed to notify SysUI of overview shown from " + (fromHome ? "home" : "app") - + ": ", e); - } + SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(fromHome, tag); } private void setupPackageListener() { diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java new file mode 100644 index 0000000000..f37e679ef7 --- /dev/null +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -0,0 +1,262 @@ +/* + * 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.quickstep; + +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + +import android.content.Context; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.IBinder; +import android.os.IBinder.DeathRecipient; +import android.os.RemoteException; +import android.util.Log; +import android.view.MotionEvent; +import com.android.launcher3.util.MainThreadInitializedObject; +import com.android.quickstep.util.SharedApiCompat; +import com.android.systemui.shared.recents.ISystemUiProxy; + +/** + * Holds the reference to SystemUI. + */ +public class SystemUiProxy implements ISystemUiProxy { + private static final String TAG = SystemUiProxy.class.getSimpleName(); + + public static final MainThreadInitializedObject INSTANCE = + new MainThreadInitializedObject<>(SystemUiProxy::new); + + private ISystemUiProxy mSystemUiProxy; + private final DeathRecipient mSystemUiProxyDeathRecipient = () -> { + MAIN_EXECUTOR.execute(() -> setProxy(null)); + }; + + // Used to dedupe calls to SystemUI + private int mLastShelfHeight; + private boolean mLastShelfVisible; + + public SystemUiProxy(Context context) { + // Do nothing + } + + @Override + public IBinder asBinder() { + // Do nothing + return null; + } + + public void setProxy(ISystemUiProxy proxy) { + unlinkToDeath(); + mSystemUiProxy = proxy; + linkToDeath(); + } + + public boolean isActive() { + return mSystemUiProxy != null; + } + + private void linkToDeath() { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.asBinder().linkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */); + } catch (RemoteException e) { + Log.e(TAG, "Failed to link sysui proxy death recipient"); + } + } + } + + private void unlinkToDeath() { + if (mSystemUiProxy != null) { + mSystemUiProxy.asBinder().unlinkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */); + } + } + + @Override + public void startScreenPinning(int taskId) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.startScreenPinning(taskId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call startScreenPinning", e); + } + } + } + + @Override + public void onSplitScreenInvoked() { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.onSplitScreenInvoked(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call onSplitScreenInvoked", e); + } + } + } + + @Override + public void onOverviewShown(boolean fromHome) { + onOverviewShown(fromHome, TAG); + } + + public void onOverviewShown(boolean fromHome, String tag) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.onOverviewShown(fromHome); + } catch (RemoteException e) { + Log.w(tag, "Failed call onOverviewShown from: " + (fromHome ? "home" : "app"), e); + } + } + } + + @Override + public Rect getNonMinimizedSplitScreenSecondaryBounds() { + if (mSystemUiProxy != null) { + try { + return mSystemUiProxy.getNonMinimizedSplitScreenSecondaryBounds(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call getNonMinimizedSplitScreenSecondaryBounds", e); + } + } + return null; + } + + @Override + public void setBackButtonAlpha(float alpha, boolean animate) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.setBackButtonAlpha(alpha, animate); + } catch (RemoteException e) { + Log.w(TAG, "Failed call setBackButtonAlpha", e); + } + } + } + + @Override + public void setNavBarButtonAlpha(float alpha, boolean animate) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.setNavBarButtonAlpha(alpha, animate); + } catch (RemoteException e) { + Log.w(TAG, "Failed call setNavBarButtonAlpha", e); + } + } + } + + @Override + public void onStatusBarMotionEvent(MotionEvent event) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.onStatusBarMotionEvent(event); + } catch (RemoteException e) { + Log.w(TAG, "Failed call onStatusBarMotionEvent", e); + } + } + } + + @Override + public void onAssistantProgress(float progress) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.onAssistantProgress(progress); + } catch (RemoteException e) { + Log.w(TAG, "Failed call onAssistantProgress with progress: " + progress, e); + } + } + } + + @Override + public void onAssistantGestureCompletion(float velocity) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.onAssistantGestureCompletion(velocity); + } catch (RemoteException e) { + Log.w(TAG, "Failed call onAssistantGestureCompletion", e); + } + } + } + + @Override + public void startAssistant(Bundle args) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.startAssistant(args); + } catch (RemoteException e) { + Log.w(TAG, "Failed call startAssistant", e); + } + } + } + + @Override + public Bundle monitorGestureInput(String name, int displayId) { + if (mSystemUiProxy != null) { + try { + return mSystemUiProxy.monitorGestureInput(name, displayId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call monitorGestureInput: " + name, e); + } + } + return null; + } + + @Override + public void notifyAccessibilityButtonClicked(int displayId) { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.notifyAccessibilityButtonClicked(displayId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call notifyAccessibilityButtonClicked", e); + } + } + } + + @Override + public void notifyAccessibilityButtonLongClicked() { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.notifyAccessibilityButtonLongClicked(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call notifyAccessibilityButtonLongClicked", e); + } + } + } + + @Override + public void stopScreenPinning() { + if (mSystemUiProxy != null) { + try { + mSystemUiProxy.stopScreenPinning(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call stopScreenPinning", e); + } + } + } + + /** + * See SharedApiCompat#setShelfHeight() + */ + public void setShelfHeight(boolean visible, int shelfHeight) { + boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight; + if (mSystemUiProxy != null && changed) { + mLastShelfVisible = visible; + mLastShelfHeight = shelfHeight; + try { + SharedApiCompat.setShelfHeight(mSystemUiProxy, visible, shelfHeight); + } catch (RemoteException e) { + Log.w(TAG, "Failed call setShelfHeight visible: " + visible + + " height: " + shelfHeight, e); + } + } + } +} diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java index f8d163230d..fb1dc0d840 100644 --- a/src/com/android/launcher3/util/UiThreadHelper.java +++ b/src/com/android/launcher3/util/UiThreadHelper.java @@ -52,15 +52,19 @@ public class UiThreadHelper { .sendToTarget(); } - public static void runAsyncCommand(Context context, AsyncCommand command, int arg1, int arg2) { - Message.obtain(getHandler(context), MSG_RUN_COMMAND, arg1, arg2, command).sendToTarget(); + public static void runAsyncCommand(Context context, AsyncCommand command, boolean arg1, + float arg2) { + Message.obtain(getHandler(context), MSG_RUN_COMMAND, arg1 ? 1 : 0, + Float.floatToIntBits(arg2), command).sendToTarget(); } private static class UiCallbacks implements Handler.Callback { + private final Context mContext; private final InputMethodManager mIMM; UiCallbacks(Context context) { + mContext = context; mIMM = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); } @@ -74,7 +78,8 @@ public class UiThreadHelper { ((Activity) message.obj).setRequestedOrientation(message.arg1); return true; case MSG_RUN_COMMAND: - ((AsyncCommand) message.obj).execute(message.arg1, message.arg2); + ((AsyncCommand) message.obj).execute(mContext, message.arg1 == 1, + Float.intBitsToFloat(message.arg2)); return true; } return false; @@ -82,7 +87,6 @@ public class UiThreadHelper { } public interface AsyncCommand { - - void execute(int arg1, int arg2); + void execute(Context proxy, boolean state, float value); } } From bfcee430fead6b795e9c7e2655ff721d0062ac80 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 1 Oct 2019 14:56:10 -0700 Subject: [PATCH 093/109] 5/ Remove OverviewInteractionState - We can move the background call to UiThreadHelper, the last sysui flags and back button alpha to SystemUiProxy (and dedupe values there as well) Bug: 141886704 Change-Id: I22183608700c6d71355597c7a08eefa19f4381fd --- .../uioverrides/RecentsUiFactory.java | 6 +- .../FlingAndHoldTouchController.java | 4 +- .../QuickSwitchTouchController.java | 4 +- .../quickstep/TouchInteractionService.java | 35 +++-- ...er.java => QuickCaptureInputConsumer.java} | 8 +- .../uioverrides/BackButtonAlphaHandler.java | 19 ++- .../launcher3/uioverrides/UiFactory.java | 20 ++- .../PortraitStatesTouchController.java | 5 +- .../quickstep/OverviewInteractionState.java | 128 ------------------ .../quickstep/SysUINavigationMode.java | 2 +- .../com/android/quickstep/SystemUiProxy.java | 25 +++- .../launcher3/util/UiThreadHelper.java | 17 ++- 12 files changed, 105 insertions(+), 168 deletions(-) rename quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/{QuickCaptureTouchConsumer.java => QuickCaptureInputConsumer.java} (96%) delete mode 100644 quickstep/src/com/android/quickstep/OverviewInteractionState.java diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index b8e9137fbc..ff73679a91 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -63,8 +63,8 @@ public abstract class RecentsUiFactory { /** * Reusable command for applying the shelf height on the background thread. */ - public static final AsyncCommand SET_SHELF_HEIGHT = (context, visible, height) -> { - SystemUiProxy.INSTANCE.get(context).setShelfHeight(visible, (int) height); + public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) -> { + SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2); }; public static RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) { @@ -209,7 +209,7 @@ public abstract class RecentsUiFactory { DeviceProfile profile = launcher.getDeviceProfile(); boolean visible = (state == NORMAL || state == OVERVIEW) && launcher.isUserActive() && !profile.isVerticalBarLayout(); - UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT, visible, + UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT, visible ? 1 : 0, profile.hotseatBarSizePx); if (state == NORMAL) { launcher.getOverviewPanel().setSwipeDownShouldLaunchApp(false); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java index e215cfe8d3..ee2e9519e5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java @@ -50,7 +50,7 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; -import com.android.quickstep.OverviewInteractionState; +import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.views.RecentsView; @@ -120,7 +120,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { * having it as part of the existing animation to the target state. */ private boolean handlingOverviewAnim() { - int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags(); + int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags(); return mStartState == NORMAL && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0; } 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 6576ec5737..5c3b55d6c4 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 @@ -45,9 +45,9 @@ import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; -import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; +import com.android.quickstep.SystemUiProxy; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -82,7 +82,7 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { - int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags(); + int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags(); if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) { return NORMAL; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index d1c63819ac..0700f7b020 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -36,6 +36,7 @@ import android.app.Service; import android.app.TaskInfo; import android.content.ComponentName; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Region; import android.os.Build; @@ -52,6 +53,7 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Utilities; +import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.AppLaunchTracker; @@ -68,7 +70,7 @@ import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; -import com.android.quickstep.inputconsumers.QuickCaptureTouchConsumer; +import com.android.quickstep.inputconsumers.QuickCaptureInputConsumer; import com.android.quickstep.inputconsumers.ResetGestureInputConsumer; import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; import com.android.quickstep.util.ActiveGestureLog; @@ -115,6 +117,7 @@ public class TouchInteractionService extends Service implements private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount"; private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE"; + private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once"; private static final int MAX_BACK_NOTIFICATION_COUNT = 3; private int mBackGestureNotificationCounter = -1; @@ -237,7 +240,6 @@ public class TouchInteractionService extends Service implements private RecentsModel mRecentsModel; private OverviewCommandHelper mOverviewCommandHelper; private OverviewComponentObserver mOverviewComponentObserver; - private OverviewInteractionState mOverviewInteractionState; private InputConsumerController mInputConsumer; private RecentsAnimationDeviceState mDeviceState; @@ -309,14 +311,13 @@ public class TouchInteractionService extends Service implements } mMode = newMode; initInputMonitor(); + resetHomeBounceSeenOnQuickstepEnabledFirstTime(); } public void onUserUnlocked() { mRecentsModel = RecentsModel.INSTANCE.get(this); mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); - mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver); - mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(this); mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver); @@ -328,12 +329,31 @@ public class TouchInteractionService extends Service implements // new ModelPreload().start(this); mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this) .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT)); + resetHomeBounceSeenOnQuickstepEnabledFirstTime(); + } + + private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() { + if (!mDeviceState.isUserUnlocked() || !mMode.hasGestures) { + // Skip if not yet unlocked (can't read user shared prefs) or if the current navigation + // mode doesn't have gestures + return; + } + + // Reset home bounce seen on quick step enabled for first time + SharedPreferences sharedPrefs = Utilities.getPrefs(this); + if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) { + sharedPrefs.edit() + .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true) + .putBoolean(DiscoveryBounce.HOME_BOUNCE_SEEN, false) + .apply(); + } } @UiThread private void onSystemUiFlagsChanged() { if (mDeviceState.isUserUnlocked()) { - mOverviewInteractionState.setSystemUiStateFlags(mDeviceState.getSystemUiStateFlags()); + SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags( + mDeviceState.getSystemUiStateFlags()); mOverviewComponentObserver.onSystemUiStateChanged(); } } @@ -434,11 +454,10 @@ public class TouchInteractionService extends Service implements if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) { // Put the Compose gesture as higher priority than the Assistant or base gestures - base = new QuickCaptureTouchConsumer(this, base, - mInputMonitorCompat, mOverviewComponentObserver.getActivityControlHelper()); + base = new QuickCaptureInputConsumer(this, base, mInputMonitorCompat, + activityControl); } - if (mDeviceState.isScreenPinningActive()) { // Note: we only allow accessibility to wrap this, and it replaces the previous // base input consumer (which should be NO_OP anyway since topTaskLocked == true). diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java similarity index 96% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureTouchConsumer.java rename to quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java index 3101bb8263..ad9405f478 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureTouchConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java @@ -40,13 +40,13 @@ import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.InputMonitorCompat; /** - * Touch consumer for handling events to launch quick capture from launcher + * Input consumer for handling events to launch quick capture from launcher * @param Draggable activity subclass used by RecentsView */ -public class QuickCaptureTouchConsumer +public class QuickCaptureInputConsumer extends DelegateInputConsumer { - private static final String TAG = "QuickCaptureTouchConsumer"; + private static final String TAG = "QuickCaptureInputConsumer"; private static final String QUICK_CAPTURE_PACKAGE = "com.google.auxe.compose"; private static final String QUICK_CAPTURE_PACKAGE_DEV = "com.google.auxe.compose.debug"; @@ -72,7 +72,7 @@ public class QuickCaptureTouchConsumer private RecentsView mRecentsView; - public QuickCaptureTouchConsumer(Context context, InputConsumer delegate, + public QuickCaptureInputConsumer(Context context, InputConsumer delegate, InputMonitorCompat inputMonitor, ActivityControlHelper activityControlHelper) { super(delegate, inputMonitor); mContext = context; diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java index 693ae60f22..aa0dfc3d3b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java +++ b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java @@ -24,18 +24,18 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.anim.AnimatorSetBuilder; -import com.android.quickstep.OverviewInteractionState; +import com.android.launcher3.util.UiThreadHelper; +import com.android.quickstep.SysUINavigationMode; +import com.android.quickstep.SystemUiProxy; public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler { private static final String TAG = "BackButtonAlphaHandler"; private final Launcher mLauncher; - private final OverviewInteractionState mOverviewInteractionState; public BackButtonAlphaHandler(Launcher launcher) { mLauncher = launcher; - mOverviewInteractionState = OverviewInteractionState.INSTANCE.get(mLauncher); } @Override @@ -49,14 +49,23 @@ public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler if (!config.playNonAtomicComponent()) { return; } - float fromAlpha = mOverviewInteractionState.getBackButtonAlpha(); + + if (!SysUINavigationMode.getMode(mLauncher).hasGestures) { + // If the nav mode is not gestural, then force back button alpha to be 1 + UiThreadHelper.setBackButtonAlphaAsync(mLauncher, UiFactory.SET_BACK_BUTTON_ALPHA, 1f, + true /* animate */); + return; + } + + float fromAlpha = SystemUiProxy.INSTANCE.get(mLauncher).getLastBackButtonAlpha(); float toAlpha = toState.hideBackButton ? 0 : 1; if (Float.compare(fromAlpha, toAlpha) != 0) { ValueAnimator anim = ValueAnimator.ofFloat(fromAlpha, toAlpha); anim.setDuration(config.duration); anim.addUpdateListener(valueAnimator -> { final float alpha = (float) valueAnimator.getAnimatedValue(); - mOverviewInteractionState.setBackButtonAlpha(alpha, false); + UiThreadHelper.setBackButtonAlphaAsync(mLauncher, UiFactory.SET_BACK_BUTTON_ALPHA, + alpha, false /* animate */); }); anim.addListener(new AnimatorListenerAdapter() { @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index b0b5dcf751..17c681b26f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -51,11 +51,12 @@ import com.android.launcher3.QuickstepAppTransitionManagerImpl; import com.android.launcher3.Utilities; import com.android.launcher3.proxy.ProxyActivityStarter; import com.android.launcher3.proxy.StartActivityParams; -import com.android.quickstep.OverviewInteractionState; +import com.android.launcher3.util.UiThreadHelper; import com.android.quickstep.RecentsModel; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener; +import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.systemui.shared.system.ActivityCompat; @@ -65,6 +66,15 @@ import java.util.zip.Deflater; public class UiFactory extends RecentsUiFactory { + /** + * Reusable command for applying the back button alpha on the background thread. + */ + public static final UiThreadHelper.AsyncCommand SET_BACK_BUTTON_ALPHA = + (context, arg1, arg2) -> { + SystemUiProxy.INSTANCE.get(context).setBackButtonAlpha(Float.intBitsToFloat(arg1), + arg2 != 0); + }; + public static Runnable enableLiveUIChanges(Launcher launcher) { NavigationModeChangeListener listener = m -> { launcher.getDragLayer().recreateControllers(); @@ -88,7 +98,9 @@ public class UiFactory extends RecentsUiFactory { * Sets the back button visibility based on the current state/window focus. */ public static void onLauncherStateOrFocusChanged(Launcher launcher) { - boolean shouldBackButtonBeHidden = launcher != null + Mode mode = SysUINavigationMode.getMode(launcher); + boolean shouldBackButtonBeHidden = mode.hasGestures + && launcher != null && launcher.getStateManager().getState().hideBackButton && launcher.hasWindowFocus(); if (shouldBackButtonBeHidden) { @@ -96,8 +108,8 @@ public class UiFactory extends RecentsUiFactory { shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(launcher, TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null; } - OverviewInteractionState.INSTANCE.get(launcher) - .setBackButtonAlpha(shouldBackButtonBeHidden ? 0 : 1, true /* animate */); + UiThreadHelper.setBackButtonAlphaAsync(launcher, UiFactory.SET_BACK_BUTTON_ALPHA, + shouldBackButtonBeHidden ? 0f : 1f, true /* animate */); if (launcher != null && launcher.getDragLayer() != null) { launcher.getRootView().setDisallowBackGesture(shouldBackButtonBeHidden); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index 9813295561..ef6a5e23d6 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -47,8 +47,8 @@ import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; -import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.RecentsModel; +import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TouchInteractionService; import com.android.quickstep.util.LayoutUtils; @@ -137,8 +137,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } else if (fromState == OVERVIEW) { return isDragTowardPositive ? ALL_APPS : NORMAL; } else if (fromState == NORMAL && isDragTowardPositive) { - int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher) - .getSystemUiStateFlags(); + int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags(); return mAllowDragToOverview && TouchInteractionService.isConnected() && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0 ? OVERVIEW : ALL_APPS; diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java deleted file mode 100644 index 6b68b1952a..0000000000 --- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.quickstep; - -import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; - -import android.content.Context; -import android.os.Handler; -import android.os.Message; - -import androidx.annotation.WorkerThread; - -import com.android.launcher3.Utilities; -import com.android.launcher3.allapps.DiscoveryBounce; -import com.android.launcher3.util.MainThreadInitializedObject; - -/** - * Sets alpha for the back button - */ -public class OverviewInteractionState { - - private static final String TAG = "OverviewFlags"; - - private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once"; - - // We do not need any synchronization for this variable as its only written on UI thread. - public static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>(OverviewInteractionState::new); - - private static final int MSG_SET_BACK_BUTTON_ALPHA = 201; - - private final Context mContext; - private final Handler mUiHandler; - private final Handler mBgHandler; - - // These are updated on the background thread - private float mBackButtonAlpha = 1; - - private int mSystemUiStateFlags; - - private OverviewInteractionState(Context context) { - mContext = context; - - // Data posted to the uihandler will be sent to the bghandler. Data is sent to uihandler - // because of its high send frequency and data may be very different than the previous value - // For example, send back alpha on uihandler to avoid flickering when setting its visibility - mUiHandler = new Handler(this::handleUiMessage); - mBgHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleBgMessage); - - onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(context) - .addModeChangeListener(this::onNavigationModeChanged)); - } - - public float getBackButtonAlpha() { - return mBackButtonAlpha; - } - - public void setBackButtonAlpha(float alpha, boolean animate) { - if (!modeSupportsGestures()) { - alpha = 1; - } - mUiHandler.removeMessages(MSG_SET_BACK_BUTTON_ALPHA); - mUiHandler.obtainMessage(MSG_SET_BACK_BUTTON_ALPHA, animate ? 1 : 0, 0, alpha) - .sendToTarget(); - } - - // TODO(141886704): See if we can remove this - public void setSystemUiStateFlags(int stateFlags) { - mSystemUiStateFlags = stateFlags; - } - - public int getSystemUiStateFlags() { - return mSystemUiStateFlags; - } - - private boolean handleUiMessage(Message msg) { - if (msg.what == MSG_SET_BACK_BUTTON_ALPHA) { - mBackButtonAlpha = (float) msg.obj; - } - mBgHandler.obtainMessage(msg.what, msg.arg1, msg.arg2, msg.obj).sendToTarget(); - return true; - } - - private boolean handleBgMessage(Message msg) { - switch (msg.what) { - case MSG_SET_BACK_BUTTON_ALPHA: - applyBackButtonAlpha((float) msg.obj, msg.arg1 == 1); - return true; - } - return true; - } - - @WorkerThread - private void applyBackButtonAlpha(float alpha, boolean animate) { - SystemUiProxy.INSTANCE.get(mContext).setBackButtonAlpha(alpha, animate); - } - - private void onNavigationModeChanged(SysUINavigationMode.Mode mode) { - resetHomeBounceSeenOnQuickstepEnabledFirstTime(); - } - - private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() { - if (modeSupportsGestures() && !Utilities.getPrefs(mContext).getBoolean( - HAS_ENABLED_QUICKSTEP_ONCE, true)) { - Utilities.getPrefs(mContext).edit() - .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true) - .putBoolean(DiscoveryBounce.HOME_BOUNCE_SEEN, false) - .apply(); - } - } - - private boolean modeSupportsGestures() { - return SysUINavigationMode.getMode(mContext).hasGestures; - } -} diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java index b67c6f8c8d..5902672d5c 100644 --- a/quickstep/src/com/android/quickstep/SysUINavigationMode.java +++ b/quickstep/src/com/android/quickstep/SysUINavigationMode.java @@ -57,7 +57,7 @@ public class SysUINavigationMode { private static final String TAG = "SysUINavigationMode"; - private final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; + private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode"; diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index f37e679ef7..5539b3e393 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -46,6 +46,11 @@ public class SystemUiProxy implements ISystemUiProxy { // Used to dedupe calls to SystemUI private int mLastShelfHeight; private boolean mLastShelfVisible; + private float mLastBackButtonAlpha; + private boolean mLastBackButtonAnimate; + + // TODO(141886704): Find a way to remove this + private int mLastSystemUiStateFlags; public SystemUiProxy(Context context) { // Do nothing @@ -63,6 +68,16 @@ public class SystemUiProxy implements ISystemUiProxy { linkToDeath(); } + // TODO(141886704): Find a way to remove this + public void setLastSystemUiStateFlags(int stateFlags) { + mLastSystemUiStateFlags = stateFlags; + } + + // TODO(141886704): Find a way to remove this + public int getLastSystemUiStateFlags() { + return mLastSystemUiStateFlags; + } + public boolean isActive() { return mSystemUiProxy != null; } @@ -134,7 +149,11 @@ public class SystemUiProxy implements ISystemUiProxy { @Override public void setBackButtonAlpha(float alpha, boolean animate) { - if (mSystemUiProxy != null) { + boolean changed = Float.compare(alpha, mLastBackButtonAlpha) != 0 + || animate != mLastBackButtonAnimate; + if (mSystemUiProxy != null && changed) { + mLastBackButtonAlpha = alpha; + mLastBackButtonAnimate = animate; try { mSystemUiProxy.setBackButtonAlpha(alpha, animate); } catch (RemoteException e) { @@ -143,6 +162,10 @@ public class SystemUiProxy implements ISystemUiProxy { } } + public float getLastBackButtonAlpha() { + return mLastBackButtonAlpha; + } + @Override public void setNavBarButtonAlpha(float alpha, boolean animate) { if (mSystemUiProxy != null) { diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java index fb1dc0d840..a133f01d4e 100644 --- a/src/com/android/launcher3/util/UiThreadHelper.java +++ b/src/com/android/launcher3/util/UiThreadHelper.java @@ -23,6 +23,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.view.inputmethod.InputMethodManager; +import com.android.launcher3.uioverrides.UiFactory; /** * Utility class for offloading some class from UI thread @@ -52,10 +53,13 @@ public class UiThreadHelper { .sendToTarget(); } - public static void runAsyncCommand(Context context, AsyncCommand command, boolean arg1, - float arg2) { - Message.obtain(getHandler(context), MSG_RUN_COMMAND, arg1 ? 1 : 0, - Float.floatToIntBits(arg2), command).sendToTarget(); + public static void setBackButtonAlphaAsync(Context context, AsyncCommand command, float alpha, + boolean animate) { + runAsyncCommand(context, command, Float.floatToIntBits(alpha), animate ? 1 : 0); + } + + public static void runAsyncCommand(Context context, AsyncCommand command, int arg1, int arg2) { + Message.obtain(getHandler(context), MSG_RUN_COMMAND, arg1, arg2, command).sendToTarget(); } private static class UiCallbacks implements Handler.Callback { @@ -78,8 +82,7 @@ public class UiThreadHelper { ((Activity) message.obj).setRequestedOrientation(message.arg1); return true; case MSG_RUN_COMMAND: - ((AsyncCommand) message.obj).execute(mContext, message.arg1 == 1, - Float.intBitsToFloat(message.arg2)); + ((AsyncCommand) message.obj).execute(mContext, message.arg1, message.arg2); return true; } return false; @@ -87,6 +90,6 @@ public class UiThreadHelper { } public interface AsyncCommand { - void execute(Context proxy, boolean state, float value); + void execute(Context proxy, int arg1, int arg2); } } From 9e876a34ee29fe0f3e2ad3dd3b60355f9df00fbf Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 2 Oct 2019 11:54:14 -0700 Subject: [PATCH 094/109] 6/ Update recents animation classes to have their respective responsibilities - RecentsAnimationTargets: manages information about the targets only RecentsAnimationCallbacks: manages callbacks from WM about the animation RecentsAnimationWrapper: manages calls into WM to update the animation (to be renamed accordingly in a follow up CL) - Create the Callbacks as a part of starting the recents animation, and have the callbacks create the controller wrapper and the targets, which are both notified to the listeners through the callbacks. - Instead of passing through a callback for recents animation finished, have it be a part of the recents animation callbacks. Bug: 141886704 Change-Id: I4ff26a175654e82efe059fa74d1f310e93961dc9 --- .../android/quickstep/BaseSwipeUpHandler.java | 71 ++++++-- .../quickstep/RecentsAnimationWrapper.java | 160 ++++++++++-------- .../android/quickstep/SwipeSharedState.java | 71 ++++---- .../quickstep/TouchInteractionService.java | 7 +- .../WindowTransformSwipeHandler.java | 61 ++++--- .../DeviceLockedInputConsumer.java | 19 ++- .../FallbackNoButtonInputConsumer.java | 25 +-- .../util/RecentsAnimationCallbacks.java | 83 +++++---- .../util/RecentsAnimationTargets.java | 69 +------- .../quickstep/views/LauncherRecentsView.java | 4 +- .../android/quickstep/views/RecentsView.java | 9 +- .../util/RemoteAnimationTargets.java | 3 + 12 files changed, 311 insertions(+), 271 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index 5d7d2ff6d8..d391c46e13 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -64,15 +64,16 @@ import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.util.RecentsAnimationTargets; import com.android.quickstep.util.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; +import java.util.ArrayList; import java.util.function.Consumer; /** @@ -115,7 +116,13 @@ public abstract class BaseSwipeUpHandler mRecentsAnimationStartCallbacks = new ArrayList<>(); protected T mActivity; protected Q mRecentsView; @@ -140,8 +147,7 @@ public abstract class BaseSwipeUpHandler { mTransformParams.setSyncTransactionApplier(applier); - mRecentsAnimationWrapper.runOnInit(() -> - mRecentsAnimationWrapper.targetSet.addDependentTransactionApplier(applier)); + runOnRecentsAnimationStart(() -> + mRecentsAnimationTargets.addDependentTransactionApplier(applier)); }); mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> { @@ -219,8 +225,10 @@ public abstract class BaseSwipeUpHandler + mRecentsView.setRecentsAnimationTargets(mRecentsAnimationWrapper, + mRecentsAnimationTargets)); } protected void startNewTask(int successStateFlag, Consumer resultCallback) { @@ -256,8 +264,30 @@ public abstract class BaseSwipeUpHandler(mRecentsAnimationStartCallbacks)) { + action.run(); + } + mRecentsAnimationStartCallbacks.clear(); + } + } + + @Override + public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { + mRecentsAnimationWrapper = null; + mRecentsAnimationTargets = null; + } + + @Override + public void onRecentsAnimationFinished(RecentsAnimationWrapper controller) { + mRecentsAnimationWrapper = null; + mRecentsAnimationTargets = null; } private Rect getStackBounds(DeviceProfile dp) { @@ -370,7 +418,7 @@ public abstract class BaseSwipeUpHandler mCallbacks = new ArrayList<>(); - - public RecentsAnimationTargets targetSet; + private final RecentsAnimationControllerCompat mController; + private final Consumer mOnFinishedListener; + private final boolean mShouldMinimizeSplitScreen; private boolean mWindowThresholdCrossed = false; - private final InputConsumerController mInputConsumerController; - private final Supplier mInputProxySupplier; - + private InputConsumerController mInputConsumerController; + private Supplier mInputProxySupplier; private InputConsumer mInputConsumer; private boolean mTouchInProgress; - private boolean mFinishPending; - public RecentsAnimationWrapper(InputConsumerController inputConsumerController, - Supplier inputProxySupplier) { - mInputConsumerController = inputConsumerController; - mInputProxySupplier = inputProxySupplier; + public RecentsAnimationWrapper(RecentsAnimationControllerCompat controller, + boolean shouldMinimizeSplitScreen, + Consumer onFinishedListener) { + mController = controller; + mOnFinishedListener = onFinishedListener; + mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen; + + setWindowThresholdCrossed(mWindowThresholdCrossed); } - public boolean hasTargets() { - return targetSet != null && targetSet.hasTargets(); + /** + * Synchronously takes a screenshot of the task with the given {@param taskId} if the task is + * currently being animated. + */ + public ThumbnailData screenshotTask(int taskId) { + return mController != null ? mController.screenshotTask(taskId) : null; + } + + /** + * Indicates that the gesture has crossed the window boundary threshold and system UI can be + * update the represent the window behind + */ + public void setWindowThresholdCrossed(boolean windowThresholdCrossed) { + if (mWindowThresholdCrossed != windowThresholdCrossed) { + mWindowThresholdCrossed = windowThresholdCrossed; + UI_HELPER_EXECUTOR.execute(() -> { + mController.setAnimationTargetsBehindSystemBars(!windowThresholdCrossed); + if (mShouldMinimizeSplitScreen && windowThresholdCrossed) { + // NOTE: As a workaround for conflicting animations (Launcher animating the task + // leash, and SystemUI resizing the docked stack, which resizes the task), we + // currently only set the minimized mode, and not the inverse. + // TODO: Synchronize the minimize animation with the launcher animation + mController.setSplitScreenMinimized(windowThresholdCrossed); + } + }); + } + } + + /** + * Notifies the controller that we want to defer cancel until the next app transition starts. + * If {@param screenshot} is set, then we will receive a screenshot on the next + * {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)} and we must also call + * {@link #cleanupScreenshot()} when that screenshot is no longer used. + */ + public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { + mController.setDeferCancelUntilNextTransition(defer, screenshot); + } + + /** + * Cleans up the screenshot previously returned from + * {@link RecentsAnimationCallbacks#onAnimationCanceled(ThumbnailData)}. + */ + public void cleanupScreenshot() { + UI_HELPER_EXECUTOR.execute(() -> mController.cleanupScreenshot()); } @UiThread - public synchronized void setController(RecentsAnimationTargets targetSet) { - Preconditions.assertUIThread(); - this.targetSet = targetSet; - - if (targetSet == null) { - return; - } - targetSet.setWindowThresholdCrossed(mWindowThresholdCrossed); - - if (!mCallbacks.isEmpty()) { - for (Runnable action : new ArrayList<>(mCallbacks)) { - action.run(); - } - mCallbacks.clear(); - } + public void finishAnimationToHome() { + finishAndClear(true /* toRecents */, null, false /* sendUserLeaveHint */); } - public synchronized void runOnInit(Runnable action) { - if (targetSet == null) { - mCallbacks.add(action); - } else { - action.run(); - } + @UiThread + public void finishAnimationToApp() { + finishAndClear(false /* toRecents */, null, false /* sendUserLeaveHint */); } /** See {@link #finish(boolean, Runnable, boolean)} */ @@ -127,34 +159,36 @@ public class RecentsAnimationWrapper { private void finishAndClear(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint) { - RecentsAnimationTargets controller = targetSet; - targetSet = null; disableInputProxy(); - if (controller != null) { - controller.finishController(toRecents, onFinishComplete, sendUserLeaveHint); - } + finishController(toRecents, onFinishComplete, sendUserLeaveHint); } - public void enableInputConsumer() { - if (targetSet != null) { - targetSet.enableInputConsumer(); - } + @UiThread + public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) { + mOnFinishedListener.accept(this); + UI_HELPER_EXECUTOR.execute(() -> { + mController.setInputConsumerEnabled(false); + mController.finish(toRecents, sendUserLeaveHint); + if (callback != null) { + MAIN_EXECUTOR.execute(callback); + } + }); } /** - * Indicates that the gesture has crossed the window boundary threshold and system UI can be - * update the represent the window behind + * Enables the input consumer to start intercepting touches in the app window. */ - public void setWindowThresholdCrossed(boolean windowThresholdCrossed) { - if (mWindowThresholdCrossed != windowThresholdCrossed) { - mWindowThresholdCrossed = windowThresholdCrossed; - if (targetSet != null) { - targetSet.setWindowThresholdCrossed(windowThresholdCrossed); - } - } + public void enableInputConsumer() { + UI_HELPER_EXECUTOR.submit(() -> { + mController.hideCurrentInputMethod(); + mController.setInputConsumerEnabled(true); + }); } - public void enableInputProxy() { + public void enableInputProxy(InputConsumerController inputConsumerController, + Supplier inputProxySupplier) { + mInputProxySupplier = inputProxySupplier; + mInputConsumerController = inputConsumerController; mInputConsumerController.setInputListener(this::onInputConsumerEvent); } @@ -165,7 +199,9 @@ public class RecentsAnimationWrapper { mInputConsumer.onMotionEvent(dummyCancel); dummyCancel.recycle(); } - mInputConsumerController.setInputListener(null); + if (mInputConsumerController != null) { + mInputConsumerController.setInputListener(null); + } } private boolean onInputConsumerEvent(InputEvent ev) { @@ -214,14 +250,4 @@ public class RecentsAnimationWrapper { return true; } - - public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { - if (targetSet != null) { - targetSet.controller.setDeferCancelUntilNextTransition(defer, screenshot); - } - } - - public RecentsAnimationTargets getController() { - return targetSet; - } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java index 6b98a89abc..e09c9cb8fa 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java @@ -38,11 +38,9 @@ public class SwipeSharedState implements RecentsAnimationListener { private OverviewComponentObserver mOverviewComponentObserver; private RecentsAnimationCallbacks mRecentsAnimationListener; + private RecentsAnimationWrapper mLastRecentsAnimationController; private RecentsAnimationTargets mLastAnimationTarget; - // TODO: Remove - private Runnable mRecentsAnimationCanceledCallback; - private boolean mLastAnimationCancelled = false; private boolean mLastAnimationRunning = false; @@ -57,13 +55,35 @@ public class SwipeSharedState implements RecentsAnimationListener { } @Override - public final void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { + public final void onRecentsAnimationStart(RecentsAnimationWrapper controller, + RecentsAnimationTargets targetSet) { + mLastRecentsAnimationController = controller; mLastAnimationTarget = targetSet; mLastAnimationCancelled = false; mLastAnimationRunning = true; } + @Override + public final void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { + if (thumbnailData != null) { + mOverviewComponentObserver.getActivityControlHelper().switchToScreenshot(thumbnailData, + () -> { + mLastRecentsAnimationController.cleanupScreenshot(); + clearAnimationState(); + }); + } else { + clearAnimationState(); + } + } + + @Override + public final void onRecentsAnimationFinished(RecentsAnimationWrapper controller) { + if (mLastRecentsAnimationController == controller) { + mLastAnimationRunning = false; + } + } + private void clearAnimationTarget() { if (mLastAnimationTarget != null) { mLastAnimationTarget.release(); @@ -71,42 +91,23 @@ public class SwipeSharedState implements RecentsAnimationListener { } } - @Override - public final void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - if (thumbnailData != null) { - mOverviewComponentObserver.getActivityControlHelper().switchToScreenshot(thumbnailData, - () -> { - if (mRecentsAnimationCanceledCallback != null) { - mRecentsAnimationCanceledCallback.run(); - } - clearAnimationState(); - }); - } else { - clearAnimationState(); - } - } - - public void setRecentsAnimationCanceledCallback(Runnable callback) { - mRecentsAnimationCanceledCallback = callback; - } - private void clearAnimationState() { clearAnimationTarget(); mLastAnimationCancelled = true; mLastAnimationRunning = false; - mRecentsAnimationCanceledCallback = null; } private void clearListenerState(boolean finishAnimation) { if (mRecentsAnimationListener != null) { mRecentsAnimationListener.removeListener(this); - mRecentsAnimationListener.cancelListener(); - if (mLastAnimationRunning && mLastAnimationTarget != null) { + mRecentsAnimationListener.notifyAnimationCanceled(); + if (mLastAnimationRunning && mLastRecentsAnimationController != null) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), finishAnimation - ? mLastAnimationTarget::finishAnimation - : mLastAnimationTarget::cancelAnimation); + ? mLastRecentsAnimationController::finishAnimationToHome + : mLastRecentsAnimationController::finishAnimationToApp); + mLastRecentsAnimationController = null; mLastAnimationTarget = null; } } @@ -116,12 +117,6 @@ public class SwipeSharedState implements RecentsAnimationListener { mLastAnimationRunning = false; } - private void onSwipeAnimationFinished(RecentsAnimationTargets targetSet) { - if (mLastAnimationTarget == targetSet) { - mLastAnimationRunning = false; - } - } - public RecentsAnimationCallbacks newRecentsAnimationListenerSet() { Preconditions.assertUIThread(); @@ -137,8 +132,7 @@ public class SwipeSharedState implements RecentsAnimationListener { clearListenerState(false /* finishAnimation */); boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false : mOverviewComponentObserver.getActivityControlHelper().shouldMinimizeSplitScreen(); - mRecentsAnimationListener = new RecentsAnimationCallbacks( - shouldMinimiseSplitScreen, this::onSwipeAnimationFinished); + mRecentsAnimationListener = new RecentsAnimationCallbacks(shouldMinimiseSplitScreen); mRecentsAnimationListener.addListener(this); return mRecentsAnimationListener; } @@ -148,8 +142,9 @@ public class SwipeSharedState implements RecentsAnimationListener { } public void applyActiveRecentsAnimationState(RecentsAnimationListener listener) { - if (mLastAnimationTarget != null) { - listener.onRecentsAnimationStart(mLastAnimationTarget); + if (mLastRecentsAnimationController != null) { + listener.onRecentsAnimationStart(mLastRecentsAnimationController, + mLastAnimationTarget); } else if (mLastAnimationCancelled) { listener.onRecentsAnimationCanceled(null); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 0700f7b020..41d94714a6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -414,10 +414,9 @@ public class TouchInteractionService extends Service implements // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should // not interrupt it. QuickSwitch assumes that interruption can only happen if the // next gesture is also quick switch. - mUncheckedConsumer = - new AssistantInputConsumer(this, - mOverviewComponentObserver.getActivityControlHelper(), - InputConsumer.NO_OP, mInputMonitorCompat); + mUncheckedConsumer = new AssistantInputConsumer(this, + mOverviewComponentObserver.getActivityControlHelper(), + InputConsumer.NO_OP, mInputMonitorCompat); } else { mUncheckedConsumer = InputConsumer.NO_OP; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index b0628e55df..69928f3a2c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -291,9 +291,6 @@ public class WindowTransformSwipeHandler mStateCallback.addCallback(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK, this::notifyTransitionCancelled); - mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, - mRecentsAnimationWrapper::enableInputConsumer); - if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { mStateCallback.addChangeHandler(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT, @@ -417,7 +414,7 @@ public class WindowTransformSwipeHandler } private void sendRemoteAnimationsToAnimationFactory() { - mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationWrapper.targetSet); + mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationTargets); } private void initializeLauncherAnimationController() { @@ -464,9 +461,9 @@ public class WindowTransformSwipeHandler if (mMode != Mode.NO_BUTTON || mRecentsView == null) { return; } - RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationWrapper.targetSet == null + RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationTargets == null ? null - : mRecentsAnimationWrapper.targetSet.findTask(mRunningTaskId); + : mRecentsAnimationTargets.findTask(mRunningTaskId); final boolean recentsAttachedToAppWindow; int runningTaskIndex = mRecentsView.getRunningTaskIndex(); if (mGestureEndTarget != null) { @@ -548,15 +545,13 @@ public class WindowTransformSwipeHandler @Override public void updateFinalShift() { - - RecentsAnimationTargets controller = mRecentsAnimationWrapper.getController(); - if (controller != null) { + if (mRecentsAnimationTargets != null) { applyTransformUnchecked(); updateSysUiFlags(mCurrentShift.value); } if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - if (mRecentsAnimationWrapper.getController() != null) { + if (mRecentsAnimationTargets != null) { mLiveTileOverlay.update(mAppWindowAnimationHelper.getCurrentRectWithInsets(), mAppWindowAnimationHelper.getCurrentCornerRadius()); } @@ -599,17 +594,24 @@ public class WindowTransformSwipeHandler : centermostTask.getThumbnail().getSysUiStatusNavFlags(); boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD; // We will handle the sysui flags based on the centermost task view. - mRecentsAnimationWrapper.setWindowThresholdCrossed(centermostTaskFlags != 0 - || useHomeScreenFlags); + if (mRecentsAnimationWrapper != null) { + mRecentsAnimationWrapper.setWindowThresholdCrossed(centermostTaskFlags != 0 + || useHomeScreenFlags); + } int sysuiFlags = useHomeScreenFlags ? 0 : centermostTaskFlags; mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, sysuiFlags); } } @Override - public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { - super.onRecentsAnimationStart(targetSet); + public void onRecentsAnimationStart(RecentsAnimationWrapper controller, + RecentsAnimationTargets targetSet) { ActiveGestureLog.INSTANCE.addLog("startRecentsAnimationCallback", targetSet.apps.length); + super.onRecentsAnimationStart(controller, targetSet); + + // Only add the callback to enable the input consumer after we actually have the controller + mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, + mRecentsAnimationWrapper::enableInputConsumer); setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); mPassedOverviewThreshold = false; @@ -617,7 +619,8 @@ public class WindowTransformSwipeHandler @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - mRecentsAnimationWrapper.setController(null); + super.onRecentsAnimationCanceled(thumbnailData); + mRecentsView.setRecentsAnimationTargets(null, null); mActivityInitListener.unregister(); setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation"); @@ -707,7 +710,7 @@ public class WindowTransformSwipeHandler final GestureEndTarget endTarget; final boolean goingToNewTask; if (mRecentsView != null) { - if (!mRecentsAnimationWrapper.hasTargets()) { + if (!hasTargets()) { // If there are no running tasks, then we can assume that this is a continuation of // the last gesture, but after the recents animation has finished goingToNewTask = true; @@ -810,8 +813,9 @@ public class WindowTransformSwipeHandler } } - if (endTarget.isLauncher) { - mRecentsAnimationWrapper.enableInputProxy(); + if (endTarget.isLauncher && mRecentsAnimationWrapper != null) { + mRecentsAnimationWrapper.enableInputProxy(mInputConsumer, + this::createNewInputProxyHandler); } if (endTarget == HOME) { @@ -866,7 +870,7 @@ public class WindowTransformSwipeHandler @UiThread private void animateToProgress(float start, float end, long duration, Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) { - mRecentsAnimationWrapper.runOnInit(() -> animateToProgressInternal(start, end, duration, + runOnRecentsAnimationStart(() -> animateToProgressInternal(start, end, duration, interpolator, target, velocityPxPerMs)); } @@ -1108,25 +1112,24 @@ public class WindowTransformSwipeHandler } private void switchToScreenshot() { - RecentsAnimationTargets controller = mRecentsAnimationWrapper.getController(); if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - if (controller != null) { + if (mRecentsAnimationWrapper != null) { // Update the screenshot of the task if (mTaskSnapshot == null) { - mTaskSnapshot = controller.screenshotTask(mRunningTaskId); + mTaskSnapshot = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId); } mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot, false /* refreshNow */); } setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); - } else if (!mRecentsAnimationWrapper.hasTargets()) { + } else if (!hasTargets()) { // If there are no targets, then we don't need to capture anything setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); } else { boolean finishTransitionPosted = false; - if (controller != null) { + if (mRecentsAnimationWrapper != null) { // Update the screenshot of the task if (mTaskSnapshot == null) { - mTaskSnapshot = controller.screenshotTask(mRunningTaskId); + mTaskSnapshot = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId); } final TaskView taskView; if (mGestureEndTarget == HOME) { @@ -1155,7 +1158,7 @@ public class WindowTransformSwipeHandler private void finishCurrentTransitionToRecents() { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); - } else if (!mRecentsAnimationWrapper.hasTargets()) { + } else if (!hasTargets()) { // If there are no targets, then there is nothing to finish setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); } else { @@ -1180,8 +1183,10 @@ public class WindowTransformSwipeHandler private void setupLauncherUiAfterSwipeUpToRecentsAnimation() { endLauncherTransitionController(); mActivityControlHelper.onSwipeUpToRecentsComplete(mActivity); - mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */, - true /* screenshot */); + if (mRecentsAnimationWrapper != null) { + mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */, + true /* screenshot */); + } mRecentsView.onSwipeUpAnimationSuccess(); RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 25b4fe4f15..2d95d758bc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -42,6 +42,7 @@ import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.RecentsAnimationWrapper; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.RecentsAnimationCallbacks; @@ -91,7 +92,8 @@ public class DeviceLockedInputConsumer implements InputConsumer, private boolean mThresholdCrossed = false; - private RecentsAnimationTargets mTargetSet; + private RecentsAnimationWrapper mRecentsAnimationController; + private RecentsAnimationTargets mRecentsAnimationTargets; public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState, SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, @@ -216,8 +218,10 @@ public class DeviceLockedInputConsumer implements InputConsumer, } @Override - public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { - mTargetSet = targetSet; + public void onRecentsAnimationStart(RecentsAnimationWrapper controller, + RecentsAnimationTargets targetSet) { + mRecentsAnimationController = controller; + mRecentsAnimationTargets = targetSet; Rect displaySize = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y); RemoteAnimationTargetCompat targetCompat = targetSet.findTask(mRunningTaskId); @@ -227,7 +231,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN); displaySize.offsetTo(displaySize.left, 0); - mTransformParams.setTargetSet(mTargetSet) + mTransformParams.setTargetSet(mRecentsAnimationTargets) .setLauncherOnTop(true); mAppWindowAnimationHelper.updateTargetRect(displaySize); mAppWindowAnimationHelper.applyTransform(mTransformParams); @@ -237,12 +241,13 @@ public class DeviceLockedInputConsumer implements InputConsumer, @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - mTargetSet = null; + mRecentsAnimationController = null; + mRecentsAnimationTargets = null; } private void endRemoteAnimation() { - if (mTargetSet != null) { - mTargetSet.finishController( + if (mRecentsAnimationController != null) { + mRecentsAnimationController.finishController( false /* toRecents */, null /* callback */, false /* sendUserLeaveHint */); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 59efb2d05f..4d9ed5324a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -45,6 +45,7 @@ import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsActivity; +import com.android.quickstep.RecentsAnimationWrapper; import com.android.quickstep.RecentsModel; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.fallback.FallbackRecentsView; @@ -157,7 +158,7 @@ public class FallbackNoButtonInputConsumer extends } private void onLauncherAlphaChanged() { - if (mRecentsAnimationWrapper.targetSet != null && mEndTarget == null) { + if (mRecentsAnimationTargets != null && mEndTarget == null) { applyTransformUnchecked(); } } @@ -231,9 +232,11 @@ public class FallbackNoButtonInputConsumer extends @Override public void updateFinalShift() { mTransformParams.setProgress(mCurrentShift.value); - mRecentsAnimationWrapper.setWindowThresholdCrossed(!mInQuickSwitchMode - && (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD)); - if (mRecentsAnimationWrapper.targetSet != null) { + if (mRecentsAnimationWrapper != null) { + mRecentsAnimationWrapper.setWindowThresholdCrossed(!mInQuickSwitchMode + && (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD)); + } + if (mRecentsAnimationTargets != null) { applyTransformUnchecked(); } } @@ -333,8 +336,7 @@ public class FallbackNoButtonInputConsumer extends break; } - ThumbnailData thumbnail = - mRecentsAnimationWrapper.targetSet.controller.screenshotTask(mRunningTaskId); + ThumbnailData thumbnail = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId); mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */, false /* screenshot */); @@ -348,7 +350,7 @@ public class FallbackNoButtonInputConsumer extends Intent intent = new Intent(mOverviewComponentObserver.getOverviewIntent()) .putExtras(extras); mContext.startActivity(intent, options.toBundle()); - mRecentsAnimationWrapper.targetSet.controller.cleanupScreenshot(); + mRecentsAnimationWrapper.cleanupScreenshot(); break; } case NEW_TASK: { @@ -364,7 +366,7 @@ public class FallbackNoButtonInputConsumer extends if (mInQuickSwitchMode) { // Recalculate the end target, some views might have been initialized after // gesture has ended. - if (mRecentsView == null || !mRecentsAnimationWrapper.hasTargets()) { + if (mRecentsView == null || !hasTargets()) { mEndTarget = LAST_TASK; } else { final int runningTaskIndex = mRecentsView.getRunningTaskIndex(); @@ -414,8 +416,9 @@ public class FallbackNoButtonInputConsumer extends } @Override - public void onRecentsAnimationStart(RecentsAnimationTargets targetSet) { - super.onRecentsAnimationStart(targetSet); + public void onRecentsAnimationStart(RecentsAnimationWrapper controller, + RecentsAnimationTargets targetSet) { + super.onRecentsAnimationStart(controller, targetSet); mRecentsAnimationWrapper.enableInputConsumer(); if (mRunningOverHome) { @@ -428,7 +431,7 @@ public class FallbackNoButtonInputConsumer extends @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - mRecentsAnimationWrapper.setController(null); + mRecentsView.setRecentsAnimationTargets(null, null); setStateOnUiThread(STATE_HANDLER_INVALIDATED); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java index 415f7674b8..824b34dd05 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java @@ -26,33 +26,30 @@ import androidx.annotation.UiThread; import com.android.launcher3.Utilities; import com.android.launcher3.util.Preconditions; import com.android.quickstep.TouchInteractionService; +import com.android.quickstep.RecentsAnimationWrapper; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.Set; -import java.util.function.Consumer; /** - * Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which delegates callbacks to multiple listeners - * on the main thread + * Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which + * delegates callbacks to multiple listeners on the main thread */ public class RecentsAnimationCallbacks implements com.android.systemui.shared.system.RecentsAnimationListener { private final Set mListeners = new ArraySet<>(); private final boolean mShouldMinimizeSplitScreen; - private final Consumer mOnFinishListener; - private RecentsAnimationControllerCompat mController; + + // TODO(141886704): Remove these references when they are no longer needed + private RecentsAnimationWrapper mController; private boolean mCancelled; - public RecentsAnimationCallbacks(boolean shouldMinimizeSplitScreen, - Consumer onFinishListener) { + public RecentsAnimationCallbacks(boolean shouldMinimizeSplitScreen) { mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen; - mOnFinishListener = onFinishListener; - TouchInteractionService.getSwipeSharedState().setRecentsAnimationCanceledCallback( - () -> mController.cleanupScreenshot()); } @UiThread @@ -67,26 +64,9 @@ public class RecentsAnimationCallbacks implements mListeners.remove(listener); } - // Called only in R+ platform - @BinderThread - public final void onAnimationStart(RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - Rect homeContentInsets, Rect minimizedHomeBounds) { - mController = controller; - RecentsAnimationTargets targetSet = new RecentsAnimationTargets(controller, appTargets, - wallpaperTargets, homeContentInsets, minimizedHomeBounds, - mShouldMinimizeSplitScreen, mOnFinishListener); - - if (mCancelled) { - targetSet.cancelAnimation(); - } else { - Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { - for (RecentsAnimationListener listener : getListeners()) { - listener.onRecentsAnimationStart(targetSet); - } - }); - } + public void notifyAnimationCanceled() { + mCancelled = true; + onAnimationCanceled(null); } // Called only in Q platform @@ -99,6 +79,29 @@ public class RecentsAnimationCallbacks implements homeContentInsets, minimizedHomeBounds); } + // Called only in R+ platform + @BinderThread + public final void onAnimationStart(RecentsAnimationControllerCompat animationController, + RemoteAnimationTargetCompat[] appTargets, + RemoteAnimationTargetCompat[] wallpaperTargets, + Rect homeContentInsets, Rect minimizedHomeBounds) { + RecentsAnimationTargets targetSet = new RecentsAnimationTargets(appTargets, + wallpaperTargets, homeContentInsets, minimizedHomeBounds); + mController = new RecentsAnimationWrapper(animationController, mShouldMinimizeSplitScreen, + this::onAnimationFinished); + + if (mCancelled) { + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), + mController::finishAnimationToApp); + } else { + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { + for (RecentsAnimationListener listener : getListeners()) { + listener.onRecentsAnimationStart(mController, targetSet); + } + }); + } + } + @BinderThread @Override public final void onAnimationCanceled(ThumbnailData thumbnailData) { @@ -109,25 +112,31 @@ public class RecentsAnimationCallbacks implements }); } - private RecentsAnimationListener[] getListeners() { - return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]); + private final void onAnimationFinished(RecentsAnimationWrapper controller) { + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { + for (RecentsAnimationListener listener : getListeners()) { + listener.onRecentsAnimationFinished(controller); + } + }); } - public void cancelListener() { - mCancelled = true; - onAnimationCanceled(null); + private RecentsAnimationListener[] getListeners() { + return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]); } /** * Listener for the recents animation callbacks. */ public interface RecentsAnimationListener { - void onRecentsAnimationStart(RecentsAnimationTargets targetSet); + default void onRecentsAnimationStart(RecentsAnimationWrapper controller, + RecentsAnimationTargets targetSet) {} /** * Callback from the system when the recents animation is canceled. {@param thumbnailData} * is passed back for rendering screenshot to replace live tile. */ - void onRecentsAnimationCanceled(ThumbnailData thumbnailData); + default void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {} + + default void onRecentsAnimationFinished(RecentsAnimationWrapper controller) {} } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java index 187a404b42..4013e92bfe 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java @@ -15,41 +15,27 @@ */ package com.android.quickstep.util; -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; -import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; import android.graphics.Rect; -import com.android.systemui.shared.recents.model.ThumbnailData; -import com.android.systemui.shared.system.RecentsAnimationControllerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import java.util.function.Consumer; - /** * Extension of {@link RemoteAnimationTargets} with additional information about swipe * up animation */ public class RecentsAnimationTargets extends RemoteAnimationTargets { - private final boolean mShouldMinimizeSplitScreen; - private final Consumer mOnFinishListener; - - public final RecentsAnimationControllerCompat controller; public final Rect homeContentInsets; public final Rect minimizedHomeBounds; - public RecentsAnimationTargets(RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] apps, RemoteAnimationTargetCompat[] wallpapers, - Rect homeContentInsets, Rect minimizedHomeBounds, boolean shouldMinimizeSplitScreen, - Consumer onFinishListener) { + public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps, + RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets, + Rect minimizedHomeBounds) { super(apps, wallpapers, MODE_CLOSING); - this.controller = controller; this.homeContentInsets = homeContentInsets; this.minimizedHomeBounds = minimizedHomeBounds; - this.mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen; - this.mOnFinishListener = onFinishListener; } public boolean hasTargets() { @@ -61,52 +47,7 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets { * the actual recents animation has finished. */ public RecentsAnimationTargets cloneWithoutTargets() { - return new RecentsAnimationTargets(controller, new RemoteAnimationTargetCompat[0], - new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds, - mShouldMinimizeSplitScreen, mOnFinishListener); - } - - public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) { - mOnFinishListener.accept(this); - UI_HELPER_EXECUTOR.execute(() -> { - controller.setInputConsumerEnabled(false); - controller.finish(toRecents, sendUserLeaveHint); - - if (callback != null) { - MAIN_EXECUTOR.execute(callback); - } - }); - } - - public void enableInputConsumer() { - UI_HELPER_EXECUTOR.submit(() -> { - controller.hideCurrentInputMethod(); - controller.setInputConsumerEnabled(true); - }); - } - - public void setWindowThresholdCrossed(boolean thresholdCrossed) { - UI_HELPER_EXECUTOR.execute(() -> { - controller.setAnimationTargetsBehindSystemBars(!thresholdCrossed); - if (mShouldMinimizeSplitScreen && thresholdCrossed) { - // NOTE: As a workaround for conflicting animations (Launcher animating the task - // leash, and SystemUI resizing the docked stack, which resizes the task), we - // currently only set the minimized mode, and not the inverse. - // TODO: Synchronize the minimize animation with the launcher animation - controller.setSplitScreenMinimized(thresholdCrossed); - } - }); - } - - public ThumbnailData screenshotTask(int taskId) { - return controller != null ? controller.screenshotTask(taskId) : null; - } - - public void cancelAnimation() { - finishController(false /* toRecents */, null, false /* sendUserLeaveHint */); - } - - public void finishAnimation() { - finishController(true /* toRecents */, null, false /* sendUserLeaveHint */); + return new RecentsAnimationTargets(new RemoteAnimationTargetCompat[0], + new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 0f9184f48d..6a6043cec7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -221,7 +221,7 @@ public class LauncherRecentsView extends RecentsView implements StateL public AppWindowAnimationHelper.TransformParams getLiveTileParams( boolean mightNeedToRefill) { if (!mEnableDrawingLiveTile || mRecentsAnimationWrapper == null - || mAppWindowAnimationHelper == null) { + || mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) { return null; } TaskView taskView = getRunningTaskView(); @@ -245,7 +245,7 @@ public class LauncherRecentsView extends RecentsView implements StateL mTransformParams.setProgress(1f) .setCurrentRectAndTargetAlpha(mTempRectF, taskView.getAlpha()) .setSyncTransactionApplier(mSyncTransactionApplier) - .setTargetSet(mRecentsAnimationWrapper.targetSet) + .setTargetSet(mRecentsAnimationTargets) .setLauncherOnTop(true); } return mTransformParams; 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 cefe2647ee..67cd3d6bd8 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 @@ -108,6 +108,7 @@ import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; import com.android.quickstep.ViewUtils; import com.android.quickstep.util.AppWindowAnimationHelper; +import com.android.quickstep.util.RecentsAnimationTargets; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -156,6 +157,7 @@ public abstract class RecentsView extends PagedView impl }; protected RecentsAnimationWrapper mRecentsAnimationWrapper; + protected RecentsAnimationTargets mRecentsAnimationTargets; protected AppWindowAnimationHelper mAppWindowAnimationHelper; protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier; protected int mTaskWidth; @@ -808,6 +810,7 @@ public abstract class RecentsView extends PagedView impl mTaskListChangeId = -1; mRecentsAnimationWrapper = null; + mRecentsAnimationTargets = null; mAppWindowAnimationHelper = null; unloadVisibleTaskData(); @@ -1692,10 +1695,14 @@ public abstract class RecentsView extends PagedView impl public void redrawLiveTile(boolean mightNeedToRefill) { } - public void setRecentsAnimationWrapper(RecentsAnimationWrapper recentsAnimationWrapper) { + // TODO: To be removed in a follow up CL + public void setRecentsAnimationTargets(RecentsAnimationWrapper recentsAnimationWrapper, + RecentsAnimationTargets recentsAnimationTargets) { mRecentsAnimationWrapper = recentsAnimationWrapper; + mRecentsAnimationTargets = recentsAnimationTargets; } + // TODO: To be removed in a follow up CL public void setAppWindowAnimationHelper(AppWindowAnimationHelper appWindowAnimationHelper) { mAppWindowAnimationHelper = appWindowAnimationHelper; } diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java index ff726a1efe..f971c47d2e 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java @@ -86,6 +86,9 @@ public class RemoteAnimationTargets { for (RemoteAnimationTargetCompat target : unfilteredApps) { target.release(); } + for (RemoteAnimationTargetCompat target : wallpapers) { + target.release(); + } } else { applier.addAfterApplyCallback(this::release); } From d7b9db7bda6bb06cbdd6d231cb5d106372faf4eb Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 8 Oct 2019 13:07:48 -0700 Subject: [PATCH 095/109] Using SpringAnimationBuilder instead of SpringObjectAnimator in StaggeredWorkspaceAnim Change-Id: I3a7b38e3f866c95a92fbb314f0a79b0735f38c9d --- .../util/StaggeredWorkspaceAnim.java | 52 +++++++------------ 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index 1aa5365fd2..d644fd6eba 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -21,15 +21,14 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.Interpolators.LINEAR; import android.animation.Animator; -import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.view.View; import android.view.ViewGroup; import androidx.annotation.Nullable; -import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; @@ -40,14 +39,10 @@ import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Workspace; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.PropertySetter; -import com.android.launcher3.anim.SpringObjectAnimator; -import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.anim.SpringAnimationBuilder; import com.android.launcher3.graphics.OverviewScrim; import com.android.launcher3.views.IconLabelDotView; -import java.util.ArrayList; -import java.util.List; - /** * Creates an animation where all the workspace items are moved into their final location, * staggered row by row from the bottom up. @@ -69,7 +64,7 @@ public class StaggeredWorkspaceAnim { // The original view of the {@link FloatingIconView}. private final View mOriginalView; - private final List mAnimators = new ArrayList<>(); + private final AnimatorSet mAnimators = new AnimatorSet(); /** * @param floatingViewOriginalView The FloatingIconView's original view. @@ -136,16 +131,9 @@ public class StaggeredWorkspaceAnim { addScrimAnimationForState(launcher, BACKGROUND_APP, 0); addScrimAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS); - AnimatorListener resetClipListener = new AnimatorListenerAdapter() { - int numAnimations = mAnimators.size(); - + mAnimators.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - numAnimations--; - if (numAnimations > 0) { - return; - } - workspace.setClipChildren(workspaceClipChildren); workspace.setClipToPadding(workspaceClipToPadding); cellLayout.setClipChildren(cellLayoutClipChildren); @@ -153,24 +141,14 @@ public class StaggeredWorkspaceAnim { hotseat.setClipChildren(hotseatClipChildren); hotseat.setClipToPadding(hotseatClipToPadding); } - }; - - for (Animator a : mAnimators) { - a.addListener(resetClipListener); - } + }); } /** * Starts the animation. */ public void start() { - for (Animator a : mAnimators) { - if (a instanceof SpringObjectAnimator) { - ((SpringObjectAnimator) a).startSpring(1f, mVelocity, null); - } else { - a.start(); - } - } + mAnimators.start(); } /** @@ -187,10 +165,16 @@ public class StaggeredWorkspaceAnim { long startDelay = (long) ((invertedRow + 1) * APP_CLOSE_ROW_START_DELAY_MS); v.setTranslationY(mSpringTransY); - SpringObjectAnimator springTransY = new SpringObjectAnimator<>(v, VIEW_TRANSLATE_Y, - 1f, DAMPING_RATIO, STIFFNESS, mSpringTransY, 0); + + ObjectAnimator springTransY = new SpringAnimationBuilder<>(v, VIEW_TRANSLATE_Y) + .setStiffness(STIFFNESS) + .setDampingRatio(DAMPING_RATIO) + .setMinimumVisibleChange(1f) + .setEndValue(0) + .setStartVelocity(mVelocity) + .build(v.getContext()); springTransY.setStartDelay(startDelay); - mAnimators.add(springTransY); + mAnimators.play(springTransY); ObjectAnimator alpha = getAlphaAnimator(v, startDelay); if (v == mOriginalView) { @@ -211,7 +195,7 @@ public class StaggeredWorkspaceAnim { } v.setAlpha(0); - mAnimators.add(alpha); + mAnimators.play(alpha); } private ObjectAnimator getAlphaAnimator(View v, long startDelay) { @@ -229,11 +213,11 @@ public class StaggeredWorkspaceAnim { scrimAnimConfig.duration = duration; PropertySetter scrimPropertySetter = scrimAnimConfig.getPropertySetter(scrimAnimBuilder); launcher.getWorkspace().getStateTransitionAnimation().setScrim(scrimPropertySetter, state); - mAnimators.add(scrimAnimBuilder.build()); + mAnimators.play(scrimAnimBuilder.build()); Animator fadeOverviewScrim = ObjectAnimator.ofFloat( launcher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS, state.getOverviewScrimAlpha(launcher)); fadeOverviewScrim.setDuration(duration); - mAnimators.add(fadeOverviewScrim); + mAnimators.play(fadeOverviewScrim); } } From d3da92ac664d17e210b86f4eb2579cb3ccb4364b Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 2 Oct 2019 17:29:58 -0700 Subject: [PATCH 096/109] 7/ Rename RecentsAnimationWrapper - Move the recents animation classes out of util into base quickstep pkg - Clean up some local var names Bug: 141886704 Change-Id: I1556179e203cbb43b77ea58e6fe520aa9944099b --- .../AppToOverviewAnimationProvider.java | 5 +-- .../FallbackActivityControllerHelper.java | 1 - .../quickstep/OverviewCommandHelper.java | 12 +++--- .../quickstep/TouchInteractionService.java | 2 +- .../AppToOverviewAnimationProvider.java | 9 ++-- .../android/quickstep/BaseSwipeUpHandler.java | 32 +++++++------- .../FallbackActivityControllerHelper.java | 1 - .../quickstep/OverviewCommandHelper.java | 17 +++++--- .../android/quickstep/SwipeSharedState.java | 16 ++++--- .../com/android/quickstep/TaskViewUtils.java | 11 +++-- .../quickstep/TouchInteractionService.java | 16 ++++++- .../WindowTransformSwipeHandler.java | 42 +++++++++---------- .../AccessibilityInputConsumer.java | 1 + .../AssistantInputConsumer.java | 1 + .../inputconsumers/DelegateInputConsumer.java | 1 + .../DeviceLockedInputConsumer.java | 25 ++++++----- .../FallbackNoButtonInputConsumer.java | 31 +++++++------- .../OtherActivityInputConsumer.java | 10 ++--- .../inputconsumers/OverviewInputConsumer.java | 1 + .../OverviewWithoutFocusInputConsumer.java | 1 + .../QuickCaptureInputConsumer.java | 1 + .../ResetGestureInputConsumer.java | 1 + .../ScreenPinnedInputConsumer.java | 1 + .../util/AppWindowAnimationHelper.java | 1 + .../quickstep/views/LauncherRecentsView.java | 2 +- .../android/quickstep/views/RecentsView.java | 16 +++---- .../QuickstepAppTransitionManagerImpl.java | 2 +- .../quickstep/ActivityControlHelper.java | 1 - .../com/android/quickstep}/InputConsumer.java | 2 +- .../quickstep}/RecentsAnimationCallbacks.java | 20 ++++----- .../RecentsAnimationController.java} | 14 +++---- .../quickstep}/RecentsAnimationTargets.java | 2 +- .../{util => }/RemoteAnimationTargets.java | 2 +- .../util/RemoteFadeOutAnimationListener.java | 1 + 34 files changed, 157 insertions(+), 144 deletions(-) rename quickstep/{recents_ui_overrides/src/com/android/quickstep/inputconsumers => src/com/android/quickstep}/InputConsumer.java (98%) rename quickstep/{recents_ui_overrides/src/com/android/quickstep/util => src/com/android/quickstep}/RecentsAnimationCallbacks.java (88%) rename quickstep/{recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java => src/com/android/quickstep/RecentsAnimationController.java} (94%) rename quickstep/{recents_ui_overrides/src/com/android/quickstep/util => src/com/android/quickstep}/RecentsAnimationTargets.java (98%) rename quickstep/src/com/android/quickstep/{util => }/RemoteAnimationTargets.java (98%) diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java index b1a388133c..f31cf37d0f 100644 --- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -32,7 +32,6 @@ import android.util.Log; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAnimationRunner; import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.IconRecentsView; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; @@ -113,9 +112,9 @@ final class AppToOverviewAnimationProvider imple return anim; } - RemoteAnimationTargets targetSet = + RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING); - mRecentsView.setTransitionedFromApp(!targetSet.isAnimatingHome()); + mRecentsView.setTransitionedFromApp(!targets.isAnimatingHome()); RemoteAnimationTargetCompat recentsTarget = null; RemoteAnimationTargetCompat closingAppTarget = null; diff --git a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java index 37c2c04306..ee860ab2cd 100644 --- a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java +++ b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java @@ -27,7 +27,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.IconRecentsView; import java.util.function.BiPredicate; diff --git a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 9c409ccca5..f65109afde 100644 --- a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -40,26 +40,28 @@ import com.android.systemui.shared.system.LatencyTrackerCompat; public class OverviewCommandHelper { private final Context mContext; - private final ActivityManagerWrapper mAM; + private final RecentsAnimationDeviceState mDeviceState; private final RecentsModel mRecentsModel; private final OverviewComponentObserver mOverviewComponentObserver; private long mLastToggleTime; - public OverviewCommandHelper(Context context, OverviewComponentObserver observer) { + public OverviewCommandHelper(Context context, RecentsAnimationDeviceState deviceState, + OverviewComponentObserver observer) { mContext = context; - mAM = ActivityManagerWrapper.getInstance(); + mDeviceState = deviceState; mRecentsModel = RecentsModel.INSTANCE.get(mContext); mOverviewComponentObserver = observer; } public void onOverviewToggle() { // If currently screen pinning, do not enter overview - if (mAM.isScreenPinningActive()) { + if (mDeviceState.isScreenPinningActive()) { return; } - mAM.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); + ActivityManagerWrapper.getInstance() + .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); MAIN_EXECUTOR.execute(new RecentsActivityCommand<>()); } diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java index 0012ad4e98..f743663326 100644 --- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -148,7 +148,7 @@ public class TouchInteractionService extends Service { public void onUserUnlocked() { mRecentsModel = RecentsModel.INSTANCE.get(this); mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); - mOverviewCommandHelper = new OverviewCommandHelper(this, + mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState, mOverviewComponentObserver); } 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 1b49732cb2..3eab5ac873 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -32,7 +32,6 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; @@ -115,11 +114,11 @@ final class AppToOverviewAnimationProvider imple return anim; } - RemoteAnimationTargets targetSet = new RemoteAnimationTargets(appTargets, + RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING); // Use the top closing app to determine the insets for the animation - RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mTargetTaskId); + RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId); if (runningTaskTarget == null) { Log.e(TAG, "No closing app"); anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION)); @@ -149,12 +148,12 @@ final class AppToOverviewAnimationProvider imple valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); valueAnimator.addUpdateListener((v) -> { params.setProgress((float) v.getAnimatedValue()) - .setTargetSet(targetSet) + .setTargetSet(targets) .setLauncherOnTop(true); clipHelper.applyTransform(params); }); - if (targetSet.isAnimatingHome()) { + if (targets.isAnimatingHome()) { // If we are animating home, fade in the opening targets RemoteAnimationTargets openingSet = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index d391c46e13..9eb2d4c919 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -58,14 +58,12 @@ import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.RecentsAnimationTargets; -import com.android.quickstep.util.RecentsAnimationCallbacks.RecentsAnimationListener; +import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -118,7 +116,7 @@ public abstract class BaseSwipeUpHandler - mRecentsView.setRecentsAnimationTargets(mRecentsAnimationWrapper, + mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController, mRecentsAnimationTargets)); } @@ -240,7 +238,7 @@ public abstract class BaseSwipeUpHandler { + mRecentsAnimationController.finish(true /* toRecents */, () -> { if (!mCanceled) { TaskView nextTask = mRecentsView.getTaskView(taskId); if (nextTask != null) { @@ -284,17 +282,17 @@ public abstract class BaseSwipeUpHandler()); } + @BinderThread public void onOverviewShown(boolean triggeredFromAltTab) { MAIN_EXECUTOR.execute(new ShowRecentsCommand(triggeredFromAltTab)); } + @BinderThread public void onOverviewHidden() { MAIN_EXECUTOR.execute(new HideRecentsCommand()); } + @BinderThread public void onTip(int actionType, int viewType) { MAIN_EXECUTOR.execute(() -> UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType)); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java index e09c9cb8fa..7beab5bae1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java @@ -22,9 +22,7 @@ import android.util.Log; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.Preconditions; -import com.android.quickstep.util.RecentsAnimationCallbacks; -import com.android.quickstep.util.RecentsAnimationTargets; -import com.android.quickstep.util.RecentsAnimationCallbacks.RecentsAnimationListener; +import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -38,7 +36,7 @@ public class SwipeSharedState implements RecentsAnimationListener { private OverviewComponentObserver mOverviewComponentObserver; private RecentsAnimationCallbacks mRecentsAnimationListener; - private RecentsAnimationWrapper mLastRecentsAnimationController; + private RecentsAnimationController mLastRecentsAnimationController; private RecentsAnimationTargets mLastAnimationTarget; private boolean mLastAnimationCancelled = false; @@ -55,10 +53,10 @@ public class SwipeSharedState implements RecentsAnimationListener { } @Override - public final void onRecentsAnimationStart(RecentsAnimationWrapper controller, - RecentsAnimationTargets targetSet) { + public final void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { mLastRecentsAnimationController = controller; - mLastAnimationTarget = targetSet; + mLastAnimationTarget = targets; mLastAnimationCancelled = false; mLastAnimationRunning = true; @@ -78,7 +76,7 @@ public class SwipeSharedState implements RecentsAnimationListener { } @Override - public final void onRecentsAnimationFinished(RecentsAnimationWrapper controller) { + public final void onRecentsAnimationFinished(RecentsAnimationController controller) { if (mLastRecentsAnimationController == controller) { mLastAnimationRunning = false; } @@ -117,7 +115,7 @@ public class SwipeSharedState implements RecentsAnimationListener { mLastAnimationRunning = false; } - public RecentsAnimationCallbacks newRecentsAnimationListenerSet() { + public RecentsAnimationCallbacks newRecentsAnimationCallbacks() { Preconditions.assertUIThread(); if (mLastAnimationRunning) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java index b55fd8b54d..2522c0fb96 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java @@ -33,7 +33,6 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.Utilities; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.MultiValueUpdateListener; -import com.android.quickstep.util.RemoteAnimationTargets; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; @@ -121,13 +120,13 @@ public final class TaskViewUtils { RemoteAnimationTargetCompat[] wallpaperTargets, final AppWindowAnimationHelper inOutHelper) { SyncRtSurfaceTransactionApplierCompat applier = new SyncRtSurfaceTransactionApplierCompat(v); - final RemoteAnimationTargets targetSet = + final RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING); - targetSet.addDependentTransactionApplier(applier); + targets.addDependentTransactionApplier(applier); AppWindowAnimationHelper.TransformParams params = new AppWindowAnimationHelper.TransformParams() .setSyncTransactionApplier(applier) - .setTargetSet(targetSet) + .setTargetSet(targets) .setLauncherOnTop(true); final RecentsView recentsView = v.getRecentsView(); @@ -149,7 +148,7 @@ public final class TaskViewUtils { BaseActivity.fromContext(v.getContext()).getDeviceProfile(), true /* isOpening */); inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), - targetSet.apps.length == 0 ? null : targetSet.apps[0]); + targets.apps.length == 0 ? null : targets.apps[0]); mThumbnailRect = new RectF(inOutHelper.getTargetRect()); mThumbnailRect.offset(-v.getTranslationX(), -v.getTranslationY()); @@ -203,7 +202,7 @@ public final class TaskViewUtils { appAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - targetSet.release(); + targets.release(); } }); return appAnimator; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 41d94714a6..2616d0dff9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -48,6 +48,7 @@ import android.view.Choreographer; import android.view.InputEvent; import android.view.MotionEvent; +import androidx.annotation.BinderThread; import androidx.annotation.UiThread; import androidx.annotation.WorkerThread; @@ -66,7 +67,6 @@ import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; import com.android.quickstep.inputconsumers.AssistantInputConsumer; import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; import com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer; -import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OtherActivityInputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; @@ -123,6 +123,7 @@ public class TouchInteractionService extends Service implements private final IBinder mMyBinder = new IOverviewProxy.Stub() { + @BinderThread public void onInitialize(Bundle bundle) { ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); @@ -133,16 +134,19 @@ public class TouchInteractionService extends Service implements sIsInitialized = true; } + @BinderThread @Override public void onOverviewToggle() { mOverviewCommandHelper.onOverviewToggle(); } + @BinderThread @Override public void onOverviewShown(boolean triggeredFromAltTab) { mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab); } + @BinderThread @Override public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { if (triggeredFromAltTab && !triggeredFromHomeKey) { @@ -151,23 +155,27 @@ public class TouchInteractionService extends Service implements } } + @BinderThread @Override public void onTip(int actionType, int viewType) { mOverviewCommandHelper.onTip(actionType, viewType); } + @BinderThread @Override public void onAssistantAvailable(boolean available) { MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantAvailable(available)); MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged); } + @BinderThread @Override public void onAssistantVisibilityChanged(float visibility) { MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantVisibility(visibility)); MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged); } + @BinderThread public void onBackAction(boolean completed, int downX, int downY, boolean isButton, boolean gestureSwipeLeft) { if (mOverviewComponentObserver == null) { @@ -184,11 +192,13 @@ public class TouchInteractionService extends Service implements } } + @BinderThread public void onSystemUiStateChanged(int stateFlags) { MAIN_EXECUTOR.execute(() -> mDeviceState.setSystemUiFlags(stateFlags)); MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged); } + @BinderThread public void onActiveNavBarRegionChanges(Region region) { MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region)); } @@ -314,10 +324,12 @@ public class TouchInteractionService extends Service implements resetHomeBounceSeenOnQuickstepEnabledFirstTime(); } + @UiThread public void onUserUnlocked() { mRecentsModel = RecentsModel.INSTANCE.get(this); mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); - mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver); + mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState, + mOverviewComponentObserver); mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 69928f3a2c..ccc41e3de0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -75,12 +75,10 @@ import com.android.quickstep.ActivityControlHelper.AnimationFactory; import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState; import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.RecentsAnimationTargets; import com.android.quickstep.views.LiveTileOverlay; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -594,8 +592,8 @@ public class WindowTransformSwipeHandler : centermostTask.getThumbnail().getSysUiStatusNavFlags(); boolean useHomeScreenFlags = windowProgress > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD; // We will handle the sysui flags based on the centermost task view. - if (mRecentsAnimationWrapper != null) { - mRecentsAnimationWrapper.setWindowThresholdCrossed(centermostTaskFlags != 0 + if (mRecentsAnimationController != null) { + mRecentsAnimationController.setWindowThresholdCrossed(centermostTaskFlags != 0 || useHomeScreenFlags); } int sysuiFlags = useHomeScreenFlags ? 0 : centermostTaskFlags; @@ -604,14 +602,14 @@ public class WindowTransformSwipeHandler } @Override - public void onRecentsAnimationStart(RecentsAnimationWrapper controller, - RecentsAnimationTargets targetSet) { - ActiveGestureLog.INSTANCE.addLog("startRecentsAnimationCallback", targetSet.apps.length); - super.onRecentsAnimationStart(controller, targetSet); + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { + ActiveGestureLog.INSTANCE.addLog("startRecentsAnimationCallback", targets.apps.length); + super.onRecentsAnimationStart(controller, targets); // Only add the callback to enable the input consumer after we actually have the controller mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, - mRecentsAnimationWrapper::enableInputConsumer); + mRecentsAnimationController::enableInputConsumer); setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); mPassedOverviewThreshold = false; @@ -813,8 +811,8 @@ public class WindowTransformSwipeHandler } } - if (endTarget.isLauncher && mRecentsAnimationWrapper != null) { - mRecentsAnimationWrapper.enableInputProxy(mInputConsumer, + if (endTarget.isLauncher && mRecentsAnimationController != null) { + mRecentsAnimationController.enableInputProxy(mInputConsumer, this::createNewInputProxyHandler); } @@ -1022,7 +1020,7 @@ public class WindowTransformSwipeHandler @UiThread private void resumeLastTask() { - mRecentsAnimationWrapper.finish(false /* toRecents */, null); + mRecentsAnimationController.finish(false /* toRecents */, null); ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); doLogGesture(LAST_TASK); reset(); @@ -1113,10 +1111,10 @@ public class WindowTransformSwipeHandler private void switchToScreenshot() { if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - if (mRecentsAnimationWrapper != null) { + if (mRecentsAnimationController != null) { // Update the screenshot of the task if (mTaskSnapshot == null) { - mTaskSnapshot = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId); + mTaskSnapshot = mRecentsAnimationController.screenshotTask(mRunningTaskId); } mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot, false /* refreshNow */); } @@ -1126,10 +1124,10 @@ public class WindowTransformSwipeHandler setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); } else { boolean finishTransitionPosted = false; - if (mRecentsAnimationWrapper != null) { + if (mRecentsAnimationController != null) { // Update the screenshot of the task if (mTaskSnapshot == null) { - mTaskSnapshot = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId); + mTaskSnapshot = mRecentsAnimationController.screenshotTask(mRunningTaskId); } final TaskView taskView; if (mGestureEndTarget == HOME) { @@ -1162,8 +1160,8 @@ public class WindowTransformSwipeHandler // If there are no targets, then there is nothing to finish setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); } else { - synchronized (mRecentsAnimationWrapper) { - mRecentsAnimationWrapper.finish(true /* toRecents */, + synchronized (mRecentsAnimationController) { + mRecentsAnimationController.finish(true /* toRecents */, () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } } @@ -1171,8 +1169,8 @@ public class WindowTransformSwipeHandler } private void finishCurrentTransitionToHome() { - synchronized (mRecentsAnimationWrapper) { - mRecentsAnimationWrapper.finish(true /* toRecents */, + synchronized (mRecentsAnimationController) { + mRecentsAnimationController.finish(true /* toRecents */, () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED), true /* sendUserLeaveHint */); } @@ -1183,8 +1181,8 @@ public class WindowTransformSwipeHandler private void setupLauncherUiAfterSwipeUpToRecentsAnimation() { endLauncherTransitionController(); mActivityControlHelper.onSwipeUpToRecentsComplete(mActivity); - if (mRecentsAnimationWrapper != null) { - mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */, + if (mRecentsAnimationController != null) { + mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */, true /* screenshot */); } mRecentsView.onSwipeUpAnimationSuccess(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java index f9bbd37abb..d3765c5334 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AccessibilityInputConsumer.java @@ -29,6 +29,7 @@ import android.view.VelocityTracker; import android.view.ViewConfiguration; import com.android.launcher3.R; +import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.SystemUiProxy; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java index 7cc29e4cc3..d60b92718a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java @@ -49,6 +49,7 @@ import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.InputConsumer; import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.InputMonitorCompat; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java index 311ddd27ca..0b5129c079 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java @@ -2,6 +2,7 @@ package com.android.quickstep.inputconsumers; import android.view.MotionEvent; +import com.android.quickstep.InputConsumer; import com.android.systemui.shared.system.InputMonitorCompat; public abstract class DelegateInputConsumer implements InputConsumer { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 2d95d758bc..cdf2e26bc5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -39,15 +39,15 @@ import android.view.ViewConfiguration; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.DefaultDisplay; +import com.android.quickstep.InputConsumer; import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; +import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationDeviceState; -import com.android.quickstep.RecentsAnimationWrapper; import com.android.quickstep.SwipeSharedState; +import com.android.quickstep.RecentsAnimationCallbacks; +import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.util.AppWindowAnimationHelper; -import com.android.quickstep.util.RecentsAnimationCallbacks; -import com.android.quickstep.util.RecentsAnimationTargets; - import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -92,7 +92,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, private boolean mThresholdCrossed = false; - private RecentsAnimationWrapper mRecentsAnimationController; + private RecentsAnimationController mRecentsAnimationController; private RecentsAnimationTargets mRecentsAnimationTargets; public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState, @@ -204,9 +204,8 @@ public class DeviceLockedInputConsumer implements InputConsumer, private void startRecentsTransition() { mThresholdCrossed = true; - RecentsAnimationCallbacks newListenerSet = - mSwipeSharedState.newRecentsAnimationListenerSet(); - newListenerSet.addListener(this); + RecentsAnimationCallbacks callbacks = mSwipeSharedState.newRecentsAnimationCallbacks(); + callbacks.addListener(this); Intent intent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class)) @@ -214,17 +213,17 @@ public class DeviceLockedInputConsumer implements InputConsumer, .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); mInputMonitorCompat.pilferPointers(); - startRecentsActivityAsync(intent, newListenerSet); + startRecentsActivityAsync(intent, callbacks); } @Override - public void onRecentsAnimationStart(RecentsAnimationWrapper controller, - RecentsAnimationTargets targetSet) { + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { mRecentsAnimationController = controller; - mRecentsAnimationTargets = targetSet; + mRecentsAnimationTargets = targets; Rect displaySize = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y); - RemoteAnimationTargetCompat targetCompat = targetSet.findTask(mRunningTaskId); + RemoteAnimationTargetCompat targetCompat = targets.findTask(mRunningTaskId); if (targetCompat != null) { mAppWindowAnimationHelper.updateSource(displaySize, targetCompat); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 4d9ed5324a..29357f237d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -42,15 +42,16 @@ import com.android.launcher3.util.ObjectWrapper; import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseSwipeUpHandler; +import com.android.quickstep.InputConsumer; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsActivity; -import com.android.quickstep.RecentsAnimationWrapper; +import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsModel; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.RecentsAnimationTargets; +import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -232,8 +233,8 @@ public class FallbackNoButtonInputConsumer extends @Override public void updateFinalShift() { mTransformParams.setProgress(mCurrentShift.value); - if (mRecentsAnimationWrapper != null) { - mRecentsAnimationWrapper.setWindowThresholdCrossed(!mInQuickSwitchMode + if (mRecentsAnimationController != null) { + mRecentsAnimationController.setWindowThresholdCrossed(!mInQuickSwitchMode && (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD)); } if (mRecentsAnimationTargets != null) { @@ -319,25 +320,25 @@ public class FallbackNoButtonInputConsumer extends switch (mEndTarget) { case HOME: { if (mSwipeUpOverHome) { - mRecentsAnimationWrapper.finish(false, null, false); + mRecentsAnimationController.finish(false, null, false); // Send a home intent to clear the task stack mContext.startActivity(mOverviewComponentObserver.getHomeIntent()); } else { - mRecentsAnimationWrapper.finish(true, null, true); + mRecentsAnimationController.finish(true, null, true); } break; } case LAST_TASK: - mRecentsAnimationWrapper.finish(false, null, false); + mRecentsAnimationController.finish(false, null, false); break; case RECENTS: { if (mSwipeUpOverHome) { - mRecentsAnimationWrapper.finish(true, null, true); + mRecentsAnimationController.finish(true, null, true); break; } - ThumbnailData thumbnail = mRecentsAnimationWrapper.screenshotTask(mRunningTaskId); - mRecentsAnimationWrapper.setDeferCancelUntilNextTransition(true /* defer */, + ThumbnailData thumbnail = mRecentsAnimationController.screenshotTask(mRunningTaskId); + mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */, false /* screenshot */); ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0); @@ -350,7 +351,7 @@ public class FallbackNoButtonInputConsumer extends Intent intent = new Intent(mOverviewComponentObserver.getOverviewIntent()) .putExtras(extras); mContext.startActivity(intent, options.toBundle()); - mRecentsAnimationWrapper.cleanupScreenshot(); + mRecentsAnimationController.cleanupScreenshot(); break; } case NEW_TASK: { @@ -416,10 +417,10 @@ public class FallbackNoButtonInputConsumer extends } @Override - public void onRecentsAnimationStart(RecentsAnimationWrapper controller, - RecentsAnimationTargets targetSet) { - super.onRecentsAnimationStart(controller, targetSet); - mRecentsAnimationWrapper.enableInputConsumer(); + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { + super.onRecentsAnimationStart(controller, targets); + mRecentsAnimationController.enableInputConsumer(); if (mRunningOverHome) { mAppWindowAnimationHelper.prepareAnimation(mDp, true); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 3e66d7b1a4..d5a18043ab 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -53,6 +53,7 @@ import com.android.launcher3.util.TraceHelper; import com.android.quickstep.ActivityControlHelper; import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.BaseSwipeUpHandler.Factory; +import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; @@ -61,7 +62,7 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; -import com.android.quickstep.util.RecentsAnimationCallbacks; +import com.android.quickstep.RecentsAnimationCallbacks; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; @@ -343,12 +344,11 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mSwipeSharedState.applyActiveRecentsAnimationState(handler); notifyGestureStarted(); } else { - RecentsAnimationCallbacks newListenerSet = - mSwipeSharedState.newRecentsAnimationListenerSet(); - newListenerSet.addListener(handler); + RecentsAnimationCallbacks callbacks = mSwipeSharedState.newRecentsAnimationCallbacks(); + callbacks.addListener(handler); Intent intent = handler.getLaunchIntent(); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); - startRecentsActivityAsync(intent, newListenerSet); + startRecentsActivityAsync(intent, callbacks); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index 74e457c686..b09a5ac1c1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -27,6 +27,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Utilities; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.InputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java index 03e0ae77e5..c2560946c3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -36,6 +36,7 @@ import com.android.launcher3.logging.StatsLogUtils; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.InputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.NavBarPosition; import com.android.systemui.shared.system.ActivityManagerWrapper; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java index ad9405f478..ea80a383bd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java @@ -36,6 +36,7 @@ import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.InputConsumer; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.InputMonitorCompat; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java index 8eede81b84..e04c0c741c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java @@ -17,6 +17,7 @@ package com.android.quickstep.inputconsumers; import android.view.MotionEvent; +import com.android.quickstep.InputConsumer; import com.android.quickstep.SwipeSharedState; /** diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java index cfd9d91428..d8b1bfdcfd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java @@ -22,6 +22,7 @@ import android.view.MotionEvent; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.InputConsumer; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.SystemUiProxy; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java index c03580917c..5eee897350 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java @@ -35,6 +35,7 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherState; import com.android.launcher3.R; +import com.android.quickstep.RemoteAnimationTargets; import com.android.quickstep.SystemUiProxy; import com.android.launcher3.Utilities; import com.android.launcher3.views.BaseDragLayer; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 6a6043cec7..764e0f314f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -220,7 +220,7 @@ public class LauncherRecentsView extends RecentsView implements StateL @Override public AppWindowAnimationHelper.TransformParams getLiveTileParams( boolean mightNeedToRefill) { - if (!mEnableDrawingLiveTile || mRecentsAnimationWrapper == null + if (!mEnableDrawingLiveTile || mRecentsAnimationController == null || mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) { return null; } 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 67cd3d6bd8..ea0699159b 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 @@ -101,14 +101,14 @@ import com.android.launcher3.util.OverScroller; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.Themes; import com.android.launcher3.util.ViewPool; -import com.android.quickstep.RecentsAnimationWrapper; +import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsModel; import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; import com.android.quickstep.ViewUtils; import com.android.quickstep.util.AppWindowAnimationHelper; -import com.android.quickstep.util.RecentsAnimationTargets; +import com.android.quickstep.RecentsAnimationTargets; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -156,7 +156,7 @@ public abstract class RecentsView extends PagedView impl } }; - protected RecentsAnimationWrapper mRecentsAnimationWrapper; + protected RecentsAnimationController mRecentsAnimationController; protected RecentsAnimationTargets mRecentsAnimationTargets; protected AppWindowAnimationHelper mAppWindowAnimationHelper; protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier; @@ -809,7 +809,7 @@ public abstract class RecentsView extends PagedView impl mIgnoreResetTaskId = -1; mTaskListChangeId = -1; - mRecentsAnimationWrapper = null; + mRecentsAnimationController = null; mRecentsAnimationTargets = null; mAppWindowAnimationHelper = null; @@ -1696,9 +1696,9 @@ public abstract class RecentsView extends PagedView impl public void redrawLiveTile(boolean mightNeedToRefill) { } // TODO: To be removed in a follow up CL - public void setRecentsAnimationTargets(RecentsAnimationWrapper recentsAnimationWrapper, + public void setRecentsAnimationTargets(RecentsAnimationController recentsAnimationController, RecentsAnimationTargets recentsAnimationTargets) { - mRecentsAnimationWrapper = recentsAnimationWrapper; + mRecentsAnimationController = recentsAnimationController; mRecentsAnimationTargets = recentsAnimationTargets; } @@ -1718,14 +1718,14 @@ public abstract class RecentsView extends PagedView impl } public void finishRecentsAnimation(boolean toRecents, Runnable onFinishComplete) { - if (mRecentsAnimationWrapper == null) { + if (mRecentsAnimationController == null) { if (onFinishComplete != null) { onFinishComplete.run(); } return; } - mRecentsAnimationWrapper.finish(toRecents, onFinishComplete); + mRecentsAnimationController.finish(toRecents, onFinishComplete); } public void setDisallowScrollToClearAll(boolean disallowScrollToClearAll) { diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java index af75364023..d4db05a6c6 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -71,7 +71,7 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.quickstep.util.RemoteAnimationTargets; +import com.android.quickstep.RemoteAnimationTargets; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.QuickStepContract; diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index 132d6abe14..382232cda2 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -32,7 +32,6 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.RemoteAnimationTargets; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java similarity index 98% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java rename to quickstep/src/com/android/quickstep/InputConsumer.java index 045bafec03..62c0ded534 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/InputConsumer.java +++ b/quickstep/src/com/android/quickstep/InputConsumer.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep.inputconsumers; +package com.android.quickstep; import android.annotation.TargetApi; import android.os.Build; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java similarity index 88% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java rename to quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java index 824b34dd05..2918879d74 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationCallbacks.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep.util; +package com.android.quickstep; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -25,8 +25,6 @@ import androidx.annotation.UiThread; import com.android.launcher3.Utilities; import com.android.launcher3.util.Preconditions; -import com.android.quickstep.TouchInteractionService; -import com.android.quickstep.RecentsAnimationWrapper; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -44,7 +42,7 @@ public class RecentsAnimationCallbacks implements private final boolean mShouldMinimizeSplitScreen; // TODO(141886704): Remove these references when they are no longer needed - private RecentsAnimationWrapper mController; + private RecentsAnimationController mController; private boolean mCancelled; @@ -85,10 +83,10 @@ public class RecentsAnimationCallbacks implements RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets, Rect homeContentInsets, Rect minimizedHomeBounds) { - RecentsAnimationTargets targetSet = new RecentsAnimationTargets(appTargets, + RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets, wallpaperTargets, homeContentInsets, minimizedHomeBounds); - mController = new RecentsAnimationWrapper(animationController, mShouldMinimizeSplitScreen, - this::onAnimationFinished); + mController = new RecentsAnimationController(animationController, + mShouldMinimizeSplitScreen, this::onAnimationFinished); if (mCancelled) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), @@ -96,7 +94,7 @@ public class RecentsAnimationCallbacks implements } else { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { for (RecentsAnimationListener listener : getListeners()) { - listener.onRecentsAnimationStart(mController, targetSet); + listener.onRecentsAnimationStart(mController, targets); } }); } @@ -112,7 +110,7 @@ public class RecentsAnimationCallbacks implements }); } - private final void onAnimationFinished(RecentsAnimationWrapper controller) { + private final void onAnimationFinished(RecentsAnimationController controller) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { for (RecentsAnimationListener listener : getListeners()) { listener.onRecentsAnimationFinished(controller); @@ -128,7 +126,7 @@ public class RecentsAnimationCallbacks implements * Listener for the recents animation callbacks. */ public interface RecentsAnimationListener { - default void onRecentsAnimationStart(RecentsAnimationWrapper controller, + default void onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targetSet) {} /** @@ -137,6 +135,6 @@ public class RecentsAnimationCallbacks implements */ default void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {} - default void onRecentsAnimationFinished(RecentsAnimationWrapper controller) {} + default void onRecentsAnimationFinished(RecentsAnimationController controller) {} } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java similarity index 94% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java rename to quickstep/src/com/android/quickstep/RecentsAnimationController.java index 72aa0e79f6..d938dc5af8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -30,12 +30,8 @@ import android.view.MotionEvent; import androidx.annotation.UiThread; import com.android.launcher3.util.Preconditions; -import com.android.quickstep.inputconsumers.InputConsumer; -import com.android.quickstep.util.RecentsAnimationCallbacks; -import com.android.quickstep.util.RecentsAnimationTargets; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputConsumerController; - import com.android.systemui.shared.system.RecentsAnimationControllerCompat; import java.util.function.Consumer; @@ -44,12 +40,12 @@ import java.util.function.Supplier; /** * Wrapper around RecentsAnimationController to help with some synchronization */ -public class RecentsAnimationWrapper { +public class RecentsAnimationController { - private static final String TAG = "RecentsAnimationWrapper"; + private static final String TAG = "RecentsAnimationController"; private final RecentsAnimationControllerCompat mController; - private final Consumer mOnFinishedListener; + private final Consumer mOnFinishedListener; private final boolean mShouldMinimizeSplitScreen; private boolean mWindowThresholdCrossed = false; @@ -60,9 +56,9 @@ public class RecentsAnimationWrapper { private boolean mTouchInProgress; private boolean mFinishPending; - public RecentsAnimationWrapper(RecentsAnimationControllerCompat controller, + public RecentsAnimationController(RecentsAnimationControllerCompat controller, boolean shouldMinimizeSplitScreen, - Consumer onFinishedListener) { + Consumer onFinishedListener) { mController = controller; mOnFinishedListener = onFinishedListener; mShouldMinimizeSplitScreen = shouldMinimizeSplitScreen; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java similarity index 98% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java rename to quickstep/src/com/android/quickstep/RecentsAnimationTargets.java index 4013e92bfe..93537597d5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep.util; +package com.android.quickstep; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java similarity index 98% rename from quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java rename to quickstep/src/com/android/quickstep/RemoteAnimationTargets.java index f971c47d2e..5fa6bc79e1 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep.util; +package com.android.quickstep; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java index 7f6aba9925..fa2d3387f4 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java +++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java @@ -21,6 +21,7 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; +import com.android.quickstep.RemoteAnimationTargets; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TransactionCompat; From d7269bf8b6d47835c7cbe631b4d6a04339d4ffe7 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 4 Oct 2019 11:30:10 -0700 Subject: [PATCH 097/109] 8/ Rename ActivityControlHelper - ActivityControlHelper -> BaseActivityInterface LauncherActivityControlHelper -> LauncherActivityInterface FallbackActivityControlHelper -> FallbackActivityInterface QuickCaptureTouchConsumer -> QuickCaptureInputConsumer - Move gestures to use the activity interface from the gesture state Bug: 141886704 Change-Id: I6f12daeb03d564143404767dfe4576e3e5da2a1d --- .../AppToOverviewAnimationProvider.java | 8 +- ...er.java => FallbackActivityInterface.java} | 12 +- ...olHelper.java => GoActivityInterface.java} | 4 +- ...er.java => LauncherActivityInterface.java} | 7 +- .../quickstep/OverviewCommandHelper.java | 4 +- .../AppToOverviewAnimationProvider.java | 8 +- .../android/quickstep/BaseSwipeUpHandler.java | 20 +-- ...er.java => FallbackActivityInterface.java} | 12 +- ...er.java => LauncherActivityInterface.java} | 10 +- .../quickstep/OverviewCommandHelper.java | 22 +-- .../QuickstepTestInformationHandler.java | 2 +- .../android/quickstep/SwipeSharedState.java | 4 +- .../quickstep/TouchInteractionService.java | 127 +++++++++--------- .../WindowTransformSwipeHandler.java | 36 ++--- .../AssistantInputConsumer.java | 12 +- .../DeviceLockedInputConsumer.java | 7 +- .../FallbackNoButtonInputConsumer.java | 8 +- .../OtherActivityInputConsumer.java | 23 ++-- .../inputconsumers/OverviewInputConsumer.java | 14 +- .../OverviewWithoutFocusInputConsumer.java | 13 +- .../QuickCaptureInputConsumer.java | 11 +- .../ScreenPinnedInputConsumer.java | 7 +- ...Helper.java => BaseActivityInterface.java} | 4 +- .../com/android/quickstep/GestureState.java | 36 +++++ .../quickstep/OverviewComponentObserver.java | 16 +-- 25 files changed, 238 insertions(+), 189 deletions(-) rename go/quickstep/src/com/android/quickstep/{FallbackActivityControllerHelper.java => FallbackActivityInterface.java} (91%) rename go/quickstep/src/com/android/quickstep/{GoActivityControlHelper.java => GoActivityInterface.java} (93%) rename go/quickstep/src/com/android/quickstep/{LauncherActivityControllerHelper.java => LauncherActivityInterface.java} (94%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/{FallbackActivityControllerHelper.java => FallbackActivityInterface.java} (95%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/{LauncherActivityControllerHelper.java => LauncherActivityInterface.java} (98%) rename quickstep/src/com/android/quickstep/{ActivityControlHelper.java => BaseActivityInterface.java} (97%) create mode 100644 quickstep/src/com/android/quickstep/GestureState.java diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java index f31cf37d0f..6b50088221 100644 --- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -46,12 +46,12 @@ final class AppToOverviewAnimationProvider imple RemoteAnimationProvider { private static final String TAG = "AppToOverviewAnimationProvider"; - private final ActivityControlHelper mHelper; + private final BaseActivityInterface mHelper; private final int mTargetTaskId; private IconRecentsView mRecentsView; private AppToOverviewAnimationListener mAnimationReadyListener; - AppToOverviewAnimationProvider(ActivityControlHelper helper, int targetTaskId) { + AppToOverviewAnimationProvider(BaseActivityInterface helper, int targetTaskId) { mHelper = helper; mTargetTaskId = targetTaskId; } @@ -75,7 +75,7 @@ final class AppToOverviewAnimationProvider imple if (mAnimationReadyListener != null) { mAnimationReadyListener.onActivityReady(activity); } - ActivityControlHelper.AnimationFactory factory = + BaseActivityInterface.AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible, false /* animate activity */, (controller) -> { controller.dispatchOnStart(); @@ -85,7 +85,7 @@ final class AppToOverviewAnimationProvider imple anim.start(); }); factory.onRemoteAnimationReceived(null); - factory.createActivityController(getRecentsLaunchDuration()); + factory.createActivityInterface(getRecentsLaunchDuration()); mRecentsView = activity.getOverviewPanel(); return false; } diff --git a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java b/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java similarity index 91% rename from go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java rename to go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index ee860ab2cd..2af8441853 100644 --- a/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java +++ b/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -33,14 +33,14 @@ import java.util.function.BiPredicate; import java.util.function.Consumer; /** - * {@link ActivityControlHelper} for recents when the default launcher is different than the + * {@link BaseActivityInterface} for recents when the default launcher is different than the * currently running one and apps should interact with the {@link RecentsActivity} as opposed * to the in-launcher one. */ -public final class FallbackActivityControllerHelper extends - GoActivityControlHelper { +public final class FallbackActivityInterface extends + GoActivityInterface { - public FallbackActivityControllerHelper() { } + public FallbackActivityInterface() { } @Override public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible, @@ -63,12 +63,12 @@ public final class FallbackActivityControllerHelper extends if (!isAnimatingToRecents) { rv.setAlpha(1); } - createActivityController(getSwipeUpDestinationAndLength( + createActivityInterface(getSwipeUpDestinationAndLength( activity.getDeviceProfile(), activity, new Rect())); } @Override - public void createActivityController(long transitionLength) { + public void createActivityInterface(long transitionLength) { if (!isAnimatingToRecents) { return; } diff --git a/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java b/go/quickstep/src/com/android/quickstep/GoActivityInterface.java similarity index 93% rename from go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java rename to go/quickstep/src/com/android/quickstep/GoActivityInterface.java index 274a347cbb..5ce0f4cdf5 100644 --- a/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java +++ b/go/quickstep/src/com/android/quickstep/GoActivityInterface.java @@ -13,8 +13,8 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; * * @param activity that contains the overview */ -public abstract class GoActivityControlHelper implements - ActivityControlHelper { +public abstract class GoActivityInterface implements + BaseActivityInterface { @Override public void onTransitionCancelled(T activity, boolean activityVisible) { diff --git a/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java b/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java similarity index 94% rename from go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java rename to go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index 8993b67005..5bff8e8060 100644 --- a/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -30,10 +30,10 @@ import java.util.function.BiPredicate; import java.util.function.Consumer; /** - * {@link ActivityControlHelper} for the in-launcher recents. + * {@link BaseActivityInterface} for the in-launcher recents. * TODO: Implement the app to overview animation functionality */ -public final class LauncherActivityControllerHelper extends GoActivityControlHelper { +public final class LauncherActivityInterface extends GoActivityInterface { @Override public AnimationFactory prepareRecentsUI(Launcher activity, @@ -43,8 +43,7 @@ public final class LauncherActivityControllerHelper extends GoActivityControlHel activity.getOverviewPanel().setUsingRemoteAnimation(true); //TODO: Implement this based off where the recents view needs to be for app => recents anim. return new AnimationFactory() { - @Override - public void createActivityController(long transitionLength) { + public void createActivityInterface(long transitionLength) { callback.accept(activity.getStateManager().createAnimationToNewWorkspace( fromState, OVERVIEW, transitionLength)); } diff --git a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index f65109afde..a436ce7033 100644 --- a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -101,7 +101,7 @@ public class OverviewCommandHelper { private class RecentsActivityCommand implements Runnable { - protected final ActivityControlHelper mHelper; + protected final BaseActivityInterface mHelper; private final long mCreateTime; private final long mToggleClickedTime = SystemClock.uptimeMillis(); @@ -109,7 +109,7 @@ public class OverviewCommandHelper { private ActivityInitListener mListener; public RecentsActivityCommand() { - mHelper = mOverviewComponentObserver.getActivityControlHelper(); + mHelper = mOverviewComponentObserver.getActivityInterface(); mCreateTime = SystemClock.elapsedRealtime(); // Preload the plan 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 3eab5ac873..8a11ac80aa 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -48,14 +48,14 @@ final class AppToOverviewAnimationProvider imple private static final long RECENTS_LAUNCH_DURATION = 250; private static final String TAG = "AppToOverviewAnimationProvider"; - private final ActivityControlHelper mHelper; + private final BaseActivityInterface mHelper; // The id of the currently running task that is transitioning to overview. private final int mTargetTaskId; private T mActivity; private RecentsView mRecentsView; - AppToOverviewAnimationProvider(ActivityControlHelper helper, int targetTaskId) { + AppToOverviewAnimationProvider(BaseActivityInterface helper, int targetTaskId) { mHelper = helper; mTargetTaskId = targetTaskId; } @@ -69,7 +69,7 @@ final class AppToOverviewAnimationProvider imple boolean onActivityReady(T activity, Boolean wasVisible) { activity.getOverviewPanel().showCurrentTask(mTargetTaskId); AbstractFloatingView.closeAllOpenViews(activity, wasVisible); - ActivityControlHelper.AnimationFactory factory = + BaseActivityInterface.AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible, false /* animate activity */, (controller) -> { controller.dispatchOnStart(); @@ -79,7 +79,7 @@ final class AppToOverviewAnimationProvider imple anim.start(); }); factory.onRemoteAnimationReceived(null); - factory.createActivityController(RECENTS_LAUNCH_DURATION); + factory.createActivityInterface(RECENTS_LAUNCH_DURATION); factory.setRecentsAttachedToAppWindow(true, false); mActivity = activity; mRecentsView = mActivity.getOverviewPanel(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index 9eb2d4c919..e1e994c6a6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -56,7 +56,7 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.views.FloatingIconView; -import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; +import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; @@ -97,7 +97,7 @@ public abstract class BaseSwipeUpHandler mActivityControlHelper; + protected final BaseActivityInterface mActivityInterface; protected final RecentsModel mRecentsModel; protected final int mRunningTaskId; @@ -135,15 +135,15 @@ public abstract class BaseSwipeUpHandler { resultCallback.accept(success); if (!success) { - mActivityControlHelper.onLaunchTaskFailed(mActivity); + mActivityInterface.onLaunchTaskFailed(mActivity); nextTask.notifyTaskLaunchFailed(TAG); } else { - mActivityControlHelper.onLaunchTaskSuccess(mActivity); + mActivityInterface.onLaunchTaskSuccess(mActivity); } }, mMainThreadHandler); } @@ -291,7 +291,7 @@ public abstract class BaseSwipeUpHandler { +public final class FallbackActivityInterface implements + BaseActivityInterface { - public FallbackActivityControllerHelper() { } + public FallbackActivityInterface() { } @Override public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) { @@ -142,12 +142,12 @@ public final class FallbackActivityControllerHelper implements if (!isAnimatingToRecents) { rv.setContentAlpha(1); } - createActivityController(getSwipeUpDestinationAndLength( + createActivityInterface(getSwipeUpDestinationAndLength( activity.getDeviceProfile(), activity, new Rect())); } @Override - public void createActivityController(long transitionLength) { + public void createActivityInterface(long transitionLength) { AnimatorSet animatorSet = new AnimatorSet(); if (isAnimatingToRecents) { ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java similarity index 98% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java rename to quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java index c749761eb9..f6b3654e69 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -73,9 +73,9 @@ import java.util.function.BiPredicate; import java.util.function.Consumer; /** - * {@link ActivityControlHelper} for the in-launcher recents. + * {@link BaseActivityInterface} for the in-launcher recents. */ -public final class LauncherActivityControllerHelper implements ActivityControlHelper { +public final class LauncherActivityInterface implements BaseActivityInterface { private Runnable mAdjustInterpolatorsRunnable; @@ -214,8 +214,8 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe private boolean mIsAttachedToWindow; @Override - public void createActivityController(long transitionLength) { - createActivityControllerInternal(activity, fromState, transitionLength, callback); + public void createActivityInterface(long transitionLength) { + createActivityInterfaceInternal(activity, fromState, transitionLength, callback); // Creating the activity controller animation sometimes reapplies the launcher state // (because we set the animation as the current state animation), so we reapply the // attached state here as well to ensure recents is shown/hidden appropriately. @@ -312,7 +312,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe }; } - private void createActivityControllerInternal(Launcher activity, LauncherState fromState, + private void createActivityInterfaceInternal(Launcher activity, LauncherState fromState, long transitionLength, Consumer callback) { LauncherState endState = OVERVIEW; if (fromState == endState) { 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 6cdcb39f7d..150c44d264 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -98,14 +98,14 @@ public class OverviewCommandHelper { @Override protected boolean handleCommand(long elapsedTime) { // TODO: Go to the next page if started from alt-tab. - return mHelper.getVisibleRecentsView() != null; + return mActivityInterface.getVisibleRecentsView() != null; } @Override protected void onTransitionComplete() { // TODO(b/138729100) This doesn't execute first time launcher is run if (mTriggeredFromAltTab) { - RecentsView rv = (RecentsView) mHelper.getVisibleRecentsView(); + RecentsView rv = (RecentsView) mActivityInterface.getVisibleRecentsView(); if (rv == null) { return; } @@ -130,7 +130,7 @@ public class OverviewCommandHelper { @Override protected boolean handleCommand(long elapsedTime) { - RecentsView recents = (RecentsView) mHelper.getVisibleRecentsView(); + RecentsView recents = (RecentsView) mActivityInterface.getVisibleRecentsView(); if (recents == null) { return false; } @@ -146,7 +146,7 @@ public class OverviewCommandHelper { private class RecentsActivityCommand implements Runnable { - protected final ActivityControlHelper mHelper; + protected final BaseActivityInterface mActivityInterface; private final long mCreateTime; private final AppToOverviewAnimationProvider mAnimationProvider; @@ -155,10 +155,10 @@ public class OverviewCommandHelper { private ActivityInitListener mListener; public RecentsActivityCommand() { - mHelper = mOverviewComponentObserver.getActivityControlHelper(); + mActivityInterface = mOverviewComponentObserver.getActivityInterface(); mCreateTime = SystemClock.elapsedRealtime(); - mAnimationProvider = - new AppToOverviewAnimationProvider<>(mHelper, RecentsModel.getRunningTaskId()); + mAnimationProvider = new AppToOverviewAnimationProvider<>(mActivityInterface, + RecentsModel.getRunningTaskId()); // Preload the plan mRecentsModel.getTasks(null); @@ -174,13 +174,13 @@ public class OverviewCommandHelper { return; } - if (mHelper.switchToRecentsIfVisible(this::onTransitionComplete)) { + if (mActivityInterface.switchToRecentsIfVisible(this::onTransitionComplete)) { // If successfully switched, then return return; } // Otherwise, start overview. - mListener = mHelper.createActivityInitListener(this::onActivityReady); + mListener = mActivityInterface.createActivityInitListener(this::onActivityReady); mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(), this::createWindowAnimation, mContext, MAIN_EXECUTOR.getHandler(), mAnimationProvider.getRecentsLaunchDuration()); @@ -190,7 +190,7 @@ public class OverviewCommandHelper { // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows // the menu activity which takes window focus, preventing the right condition from // being run below - RecentsView recents = mHelper.getVisibleRecentsView(); + RecentsView recents = mActivityInterface.getVisibleRecentsView(); if (recents != null) { // Launch the next task recents.showNextTask(); @@ -207,7 +207,7 @@ public class OverviewCommandHelper { if (!mUserEventLogged) { activity.getUserEventDispatcher().logActionCommand( LauncherLogProto.Action.Command.RECENTS_BUTTON, - mHelper.getContainerType(), + mActivityInterface.getContainerType(), LauncherLogProto.ContainerType.TASKSWITCHER); mUserEventLogged = true; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index 6ac75465a3..1bbeca47f1 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -83,7 +83,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { OverviewComponentObserver observer = new OverviewComponentObserver(mContext, new RecentsAnimationDeviceState(mContext)); try { - return observer.getActivityControlHelper().getCreatedActivity().getOverviewPanel(); + return observer.getActivityInterface().getCreatedActivity().getOverviewPanel(); } finally { observer.onDestroy(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java index 7beab5bae1..cd8e1a406b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java @@ -65,7 +65,7 @@ public class SwipeSharedState implements RecentsAnimationListener { @Override public final void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { if (thumbnailData != null) { - mOverviewComponentObserver.getActivityControlHelper().switchToScreenshot(thumbnailData, + mOverviewComponentObserver.getActivityInterface().switchToScreenshot(thumbnailData, () -> { mLastRecentsAnimationController.cleanupScreenshot(); clearAnimationState(); @@ -129,7 +129,7 @@ public class SwipeSharedState implements RecentsAnimationListener { clearListenerState(false /* finishAnimation */); boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false - : mOverviewComponentObserver.getActivityControlHelper().shouldMinimizeSplitScreen(); + : mOverviewComponentObserver.getActivityInterface().shouldMinimizeSplitScreen(); mRecentsAnimationListener = new RecentsAnimationCallbacks(shouldMinimiseSplitScreen); mRecentsAnimationListener.addListener(this); return mRecentsAnimationListener; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 2616d0dff9..4b7ae6f426 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -182,10 +182,10 @@ public class TouchInteractionService extends Service implements return; } - final ActivityControlHelper activityControl = - mOverviewComponentObserver.getActivityControlHelper(); + final BaseActivityInterface activityInterface = + mOverviewComponentObserver.getActivityInterface(); UserEventDispatcher.newInstance(getBaseContext()).logActionBack(completed, downX, downY, - isButton, gestureSwipeLeft, activityControl.getContainerType()); + isButton, gestureSwipeLeft, activityInterface.getContainerType()); if (completed && !isButton && shouldNotifyBackGesture()) { UI_HELPER_EXECUTOR.execute(TouchInteractionService.this::tryNotifyBackGesture); @@ -373,7 +373,7 @@ public class TouchInteractionService extends Service implements @UiThread private void onAssistantVisibilityChanged() { if (mDeviceState.isUserUnlocked()) { - mOverviewComponentObserver.getActivityControlHelper().onAssistantVisibilityChanged( + mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged( mDeviceState.getAssistantVisibility()); } } @@ -412,13 +412,16 @@ public class TouchInteractionService extends Service implements MotionEvent event = (MotionEvent) ev; if (event.getAction() == ACTION_DOWN) { + GestureState newGestureState = new GestureState( + mOverviewComponentObserver.getActivityInterface()); + mLogId = ActiveGestureLog.INSTANCE.generateAndSetLogId(); sSwipeSharedState.setLogTraceId(mLogId); if (mDeviceState.isInSwipeUpTouchRegion(event)) { boolean useSharedState = mConsumer.useSharedSwipeState(); mConsumer.onConsumerAboutToBeSwitched(); - mConsumer = newConsumer(useSharedState, event); + mConsumer = newConsumer(newGestureState, useSharedState, event); ActiveGestureLog.INSTANCE.addLog("setInputConsumer", mConsumer.getType()); mUncheckedConsumer = mConsumer; } else if (mDeviceState.isUserUnlocked() && mMode == Mode.NO_BUTTON @@ -426,8 +429,7 @@ public class TouchInteractionService extends Service implements // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should // not interrupt it. QuickSwitch assumes that interruption can only happen if the // next gesture is also quick switch. - mUncheckedConsumer = new AssistantInputConsumer(this, - mOverviewComponentObserver.getActivityControlHelper(), + mUncheckedConsumer = new AssistantInputConsumer(this, newGestureState, InputConsumer.NO_OP, mInputMonitorCompat); } else { mUncheckedConsumer = InputConsumer.NO_OP; @@ -439,14 +441,16 @@ public class TouchInteractionService extends Service implements DejankBinderTracker.disallowBinderTrackingInTests(); } - private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) { + private InputConsumer newConsumer(GestureState gestureState, boolean useSharedState, + MotionEvent event) { boolean canStartSystemGesture = mDeviceState.canStartSystemGesture(); if (!mDeviceState.isUserUnlocked()) { if (canStartSystemGesture) { // This handles apps launched in direct boot mode (e.g. dialer) as well as apps // launched while device is locked even after exiting direct boot mode (e.g. camera). - return createDeviceLockedInputConsumer(mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT)); + return createDeviceLockedInputConsumer(gestureState, + mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT)); } else { return mResetGestureInputConsumer; } @@ -455,24 +459,21 @@ public class TouchInteractionService extends Service implements // When using sharedState, bypass systemState check as this is a followup gesture and the // first gesture started in a valid system state. InputConsumer base = canStartSystemGesture || useSharedState - ? newBaseConsumer(useSharedState, event) : mResetGestureInputConsumer; + ? newBaseConsumer(gestureState, useSharedState, event) : mResetGestureInputConsumer; if (mMode == Mode.NO_BUTTON) { - final ActivityControlHelper activityControl = - mOverviewComponentObserver.getActivityControlHelper(); if (mDeviceState.canTriggerAssistantAction(event)) { - base = new AssistantInputConsumer(this, activityControl, base, mInputMonitorCompat); + base = new AssistantInputConsumer(this, gestureState, base, mInputMonitorCompat); } if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) { // Put the Compose gesture as higher priority than the Assistant or base gestures - base = new QuickCaptureInputConsumer(this, base, mInputMonitorCompat, - activityControl); + base = new QuickCaptureInputConsumer(this, gestureState, base, mInputMonitorCompat); } if (mDeviceState.isScreenPinningActive()) { // Note: we only allow accessibility to wrap this, and it replaces the previous // base input consumer (which should be NO_OP anyway since topTaskLocked == true). - base = new ScreenPinnedInputConsumer(this, activityControl); + base = new ScreenPinnedInputConsumer(this, gestureState); } if (mDeviceState.isAccessibilityMenuAvailable()) { @@ -487,7 +488,8 @@ public class TouchInteractionService extends Service implements return base; } - private InputConsumer newBaseConsumer(boolean useSharedState, MotionEvent event) { + private InputConsumer newBaseConsumer(GestureState gestureState, boolean useSharedState, + MotionEvent event) { RunningTaskInfo runningTaskInfo = DejankBinderTracker.whitelistIpcs( () -> mAM.getRunningTask(0)); if (!useSharedState) { @@ -495,12 +497,9 @@ public class TouchInteractionService extends Service implements } if (mDeviceState.isKeyguardShowingOccluded()) { // This handles apps showing over the lockscreen (e.g. camera) - return createDeviceLockedInputConsumer(runningTaskInfo); + return createDeviceLockedInputConsumer(gestureState, runningTaskInfo); } - final ActivityControlHelper activityControl = - mOverviewComponentObserver.getActivityControlHelper(); - boolean forceOverviewInputConsumer = false; if (isExcludedAssistant(runningTaskInfo)) { // In the case where we are in the excluded assistant state, ignore it and treat the @@ -523,16 +522,18 @@ public class TouchInteractionService extends Service implements // consumer but with the next task as the running task RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); info.id = sSwipeSharedState.nextRunningTaskId; - return createOtherActivityInputConsumer(event, info); - } else if (sSwipeSharedState.goingToLauncher || activityControl.isResumed() + return createOtherActivityInputConsumer(gestureState, event, info); + } else if (sSwipeSharedState.goingToLauncher + || gestureState.getActivityInterface().isResumed() || forceOverviewInputConsumer) { - return createOverviewInputConsumer(event); - } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityControl.isInLiveTileMode()) { - return createOverviewInputConsumer(event); + return createOverviewInputConsumer(gestureState, event); + } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() + && gestureState.getActivityInterface().isInLiveTileMode()) { + return createOverviewInputConsumer(gestureState, event); } else if (mDeviceState.isGestureBlockedActivity(runningTaskInfo)) { return mResetGestureInputConsumer; } else { - return createOtherActivityInputConsumer(event, runningTaskInfo); + return createOtherActivityInputConsumer(gestureState, event, runningTaskInfo); } } @@ -542,52 +543,50 @@ public class TouchInteractionService extends Service implements && (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; } - private InputConsumer createOtherActivityInputConsumer(MotionEvent event, - RunningTaskInfo runningTaskInfo) { + private InputConsumer createOtherActivityInputConsumer(GestureState gestureState, + MotionEvent event, RunningTaskInfo runningTaskInfo) { final boolean shouldDefer; final BaseSwipeUpHandler.Factory factory; - ActivityControlHelper activityControlHelper = - mOverviewComponentObserver.getActivityControlHelper(); if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) { shouldDefer = !sSwipeSharedState.recentsAnimationFinishInterrupted; factory = mFallbackNoButtonFactory; } else { - shouldDefer = activityControlHelper.deferStartingActivity(mDeviceState, event); + shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState, + event); factory = mWindowTreansformFactory; } final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); - return new OtherActivityInputConsumer(this, mDeviceState, runningTaskInfo, shouldDefer, - this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat, - disableHorizontalSwipe, activityControlHelper, factory, mLogId); + return new OtherActivityInputConsumer(this, mDeviceState, gestureState, runningTaskInfo, + shouldDefer, this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat, + disableHorizontalSwipe, factory, mLogId); } - private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) { + private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState, + RunningTaskInfo taskInfo) { if (mMode == Mode.NO_BUTTON && taskInfo != null) { - return new DeviceLockedInputConsumer(this, mDeviceState, sSwipeSharedState, - mInputMonitorCompat, taskInfo.taskId, mLogId); + return new DeviceLockedInputConsumer(this, mDeviceState, gestureState, + sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId); } else { return mResetGestureInputConsumer; } } - public InputConsumer createOverviewInputConsumer(MotionEvent event) { - final ActivityControlHelper activityControl = - mOverviewComponentObserver.getActivityControlHelper(); - BaseDraggingActivity activity = activityControl.getCreatedActivity(); + public InputConsumer createOverviewInputConsumer(GestureState gestureState, MotionEvent event) { + BaseDraggingActivity activity = gestureState.getActivityInterface().getCreatedActivity(); if (activity == null) { return mResetGestureInputConsumer; } if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) { - return new OverviewInputConsumer(activity, mInputMonitorCompat, - false /* startingInActivityBounds */, activityControl); + return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat, + false /* startingInActivityBounds */); } else { final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); - return new OverviewWithoutFocusInputConsumer(activity, mInputMonitorCompat, - activityControl, disableHorizontalSwipe); + return new OverviewWithoutFocusInputConsumer(activity, gestureState, + mInputMonitorCompat, disableHorizontalSwipe); } } @@ -616,11 +615,11 @@ public class TouchInteractionService extends Service implements return; } - final ActivityControlHelper activityControl = - mOverviewComponentObserver.getActivityControlHelper(); - if (activityControl.getCreatedActivity() == null) { + final BaseActivityInterface activityInterface = + mOverviewComponentObserver.getActivityInterface(); + if (activityInterface.getCreatedActivity() == null) { // Make sure that UI states will be initialized. - activityControl.createActivityInitListener((activity, wasVisible) -> { + activityInterface.createActivityInitListener((activity, wasVisible) -> { AppLaunchTracker.INSTANCE.get(activity); return false; }).register(); @@ -641,9 +640,9 @@ public class TouchInteractionService extends Service implements if (!mDeviceState.isUserUnlocked()) { return; } - final ActivityControlHelper activityControl = - mOverviewComponentObserver.getActivityControlHelper(); - final BaseDraggingActivity activity = activityControl.getCreatedActivity(); + final BaseActivityInterface activityInterface = + mOverviewComponentObserver.getActivityInterface(); + final BaseDraggingActivity activity = activityInterface.getCreatedActivity(); if (activity == null || activity.isStarted()) { // We only care about the existing background activity. return; @@ -675,7 +674,7 @@ public class TouchInteractionService extends Service implements pw.println("TouchState:"); pw.println(" navMode=" + mMode); boolean resumed = mOverviewComponentObserver != null - && mOverviewComponentObserver.getActivityControlHelper().isResumed(); + && mOverviewComponentObserver.getActivityInterface().isResumed(); pw.println(" resumed=" + resumed); pw.println(" useSharedState=" + mConsumer.useSharedSwipeState()); if (mConsumer.useSharedSwipeState()) { @@ -706,16 +705,20 @@ public class TouchInteractionService extends Service implements } } - private BaseSwipeUpHandler createWindowTransformSwipeHandler(RunningTaskInfo runningTask, - long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) { - return new WindowTransformSwipeHandler(mDeviceState, runningTask, this, touchTimeMs, - mOverviewComponentObserver, continuingLastGesture, mInputConsumer, mRecentsModel); + private BaseSwipeUpHandler createWindowTransformSwipeHandler(GestureState gestureState, + RunningTaskInfo runningTask, long touchTimeMs, boolean continuingLastGesture, + boolean isLikelyToStartNewTask) { + return new WindowTransformSwipeHandler(this, mDeviceState, gestureState, runningTask, + touchTimeMs, mOverviewComponentObserver, continuingLastGesture, mInputConsumer, + mRecentsModel); } - private BaseSwipeUpHandler createFallbackNoButtonSwipeHandler(RunningTaskInfo runningTask, - long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) { - return new FallbackNoButtonInputConsumer(this, mOverviewComponentObserver, runningTask, - mRecentsModel, mInputConsumer, isLikelyToStartNewTask, continuingLastGesture); + private BaseSwipeUpHandler createFallbackNoButtonSwipeHandler(GestureState gestureState, + RunningTaskInfo runningTask, long touchTimeMs, boolean continuingLastGesture, + boolean isLikelyToStartNewTask) { + return new FallbackNoButtonInputConsumer(this, gestureState, mOverviewComponentObserver, + runningTask, mRecentsModel, mInputConsumer, isLikelyToStartNewTask, + continuingLastGesture); } protected boolean shouldNotifyBackGesture() { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index ccc41e3de0..e3b12cb79c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -26,8 +26,8 @@ import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; import static com.android.launcher3.util.RaceConditionTracker.ENTER; import static com.android.launcher3.util.RaceConditionTracker.EXIT; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; -import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.HIDE; -import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.PEEK; +import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.HIDE; +import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.PEEK; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.HOME; import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.LAST_TASK; @@ -71,9 +71,9 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.TraceHelper; -import com.android.quickstep.ActivityControlHelper.AnimationFactory; -import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState; -import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; +import com.android.quickstep.BaseActivityInterface.AnimationFactory; +import com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState; +import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.util.ActiveGestureLog; @@ -195,7 +195,8 @@ public class WindowTransformSwipeHandler */ private static final int LOG_NO_OP_PAGE_INDEX = -1; - private RecentsAnimationDeviceState mDeviceState; + private final RecentsAnimationDeviceState mDeviceState; + private final GestureState mGestureState; private GestureEndTarget mGestureEndTarget; // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise @@ -228,12 +229,13 @@ public class WindowTransformSwipeHandler private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; - public WindowTransformSwipeHandler(RecentsAnimationDeviceState deviceState, - RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, + public WindowTransformSwipeHandler(Context context, RecentsAnimationDeviceState deviceState, + GestureState gestureState, RunningTaskInfo runningTaskInfo, long touchTimeMs, OverviewComponentObserver overviewComponentObserver, boolean continuingLastGesture, InputConsumerController inputConsumer, RecentsModel recentsModel) { - super(context, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id); + super(context, gestureState, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id); mDeviceState = deviceState; + mGestureState = gestureState; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; initStateCallbacks(); @@ -349,7 +351,7 @@ public class WindowTransformSwipeHandler // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL. if (mGestureEndTarget != HOME) { Runnable initAnimFactory = () -> { - mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity, + mAnimationFactory = mActivityInterface.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible, true, this::onAnimatorPlaybackControllerCreated); maybeUpdateRecentsAttachedState(false /* animate */); @@ -518,7 +520,7 @@ public class WindowTransformSwipeHandler return; } initTransitionEndpoints(mActivity.getDeviceProfile()); - mAnimationFactory.createActivityController(mTransitionDragLength); + mAnimationFactory.createActivityInterface(mTransitionDragLength); } @Override @@ -688,9 +690,9 @@ public class WindowTransformSwipeHandler setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha); } - BaseDraggingActivity activity = mActivityControlHelper.getCreatedActivity(); + BaseDraggingActivity activity = mActivityInterface.getCreatedActivity(); return activity == null ? InputConsumer.NO_OP - : new OverviewInputConsumer(activity, null, true, mActivityControlHelper); + : new OverviewInputConsumer(mGestureState, activity, null, true); } private void endRunningWindowAnim(boolean cancel) { @@ -882,7 +884,7 @@ public class WindowTransformSwipeHandler if (mGestureEndTarget == HOME) { HomeAnimationFactory homeAnimFactory; if (mActivity != null) { - homeAnimFactory = mActivityControlHelper.prepareHomeUI(mActivity); + homeAnimFactory = mActivityInterface.prepareHomeUI(mActivity); } else { homeAnimFactory = new HomeAnimationFactory() { @NonNull @@ -994,7 +996,7 @@ public class WindowTransformSwipeHandler } // Make sure recents is in its final state maybeUpdateRecentsAttachedState(false); - mActivityControlHelper.onSwipeUpToHomeComplete(mActivity); + mActivityInterface.onSwipeUpToHomeComplete(mActivity); } }); return anim; @@ -1103,7 +1105,7 @@ public class WindowTransformSwipeHandler private void resetStateForAnimationCancel() { boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted; - mActivityControlHelper.onTransitionCancelled(mActivity, wasVisible); + mActivityInterface.onTransitionCancelled(mActivity, wasVisible); // Leave the pending invisible flag, as it may be used by wallpaper open animation. mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER); @@ -1180,7 +1182,7 @@ public class WindowTransformSwipeHandler private void setupLauncherUiAfterSwipeUpToRecentsAnimation() { endLauncherTransitionController(); - mActivityControlHelper.onSwipeUpToRecentsComplete(mActivity); + mActivityInterface.onSwipeUpToRecentsComplete(mActivity); if (mRecentsAnimationController != null) { mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */, true /* screenshot */); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java index d60b92718a..94126ff6ee 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java @@ -48,7 +48,8 @@ import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; -import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.system.InputMonitorCompat; @@ -80,7 +81,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { private long mDragTime; private float mLastProgress; private int mDirection; - private ActivityControlHelper mActivityControlHelper; + private BaseActivityInterface mActivityInterface; private final float mDragDistThreshold; private final float mFlingDistThreshold; @@ -90,7 +91,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { private final Context mContext; private final GestureDetector mGestureDetector; - public AssistantInputConsumer(Context context, ActivityControlHelper activityControlHelper, + public AssistantInputConsumer(Context context, GestureState gestureState, InputConsumer delegate, InputMonitorCompat inputMonitor) { super(delegate, inputMonitor); final Resources res = context.getResources(); @@ -103,7 +104,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { float slop = ViewConfiguration.get(context).getScaledTouchSlop(); mSquaredSlop = slop * slop; - mActivityControlHelper = activityControlHelper; + mActivityInterface = gestureState.getActivityInterface(); mGestureDetector = new GestureDetector(context, new AssistantGestureListener()); } @@ -233,8 +234,7 @@ public class AssistantInputConsumer extends DelegateInputConsumer { UserEventDispatcher.newInstance(mContext) .logActionOnContainer(gestureType, mDirection, NAVBAR); - BaseDraggingActivity launcherActivity = mActivityControlHelper - .getCreatedActivity(); + BaseDraggingActivity launcherActivity = mActivityInterface.getCreatedActivity(); if (launcherActivity != null) { launcherActivity.getRootView().performHapticFeedback( 13, // HapticFeedbackConstants.GESTURE_END diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index cdf2e26bc5..12b7c2622d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -39,6 +39,7 @@ import android.view.ViewConfiguration; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.DefaultDisplay; +import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; @@ -75,6 +76,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, private final Context mContext; private final RecentsAnimationDeviceState mDeviceState; + private final GestureState mGestureState; private final float mTouchSlopSquared; private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; @@ -96,10 +98,11 @@ public class DeviceLockedInputConsumer implements InputConsumer, private RecentsAnimationTargets mRecentsAnimationTargets; public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState, - SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, - int runningTaskId, int logId) { + GestureState gestureState, SwipeSharedState swipeSharedState, + InputMonitorCompat inputMonitorCompat, int runningTaskId, int logId) { mContext = context; mDeviceState = deviceState; + mGestureState = gestureState; mTouchSlopSquared = squaredTouchSlop(context); mSwipeSharedState = swipeSharedState; mAppWindowAnimationHelper = new AppWindowAnimationHelper(context); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 29357f237d..370b48793c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -39,9 +39,10 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.ObjectWrapper; -import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; +import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseSwipeUpHandler; +import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.OverviewComponentObserver; @@ -114,12 +115,13 @@ public class FallbackNoButtonInputConsumer extends private final PointF mEndVelocityPxPerMs = new PointF(0, 0.5f); private RunningWindowAnim mFinishAnimation; - public FallbackNoButtonInputConsumer(Context context, + public FallbackNoButtonInputConsumer(Context context, GestureState gestureState, OverviewComponentObserver overviewComponentObserver, RunningTaskInfo runningTaskInfo, RecentsModel recentsModel, InputConsumerController inputConsumer, boolean isLikelyToStartNewTask, boolean continuingLastGesture) { - super(context, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id); + super(context, gestureState, overviewComponentObserver, recentsModel, inputConsumer, + runningTaskInfo.id); mLauncherAlpha.value = 1; mRunningTaskInfo = runningTaskInfo; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index d5a18043ab..fbedc0f812 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -50,9 +50,10 @@ import com.android.launcher3.R; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RaceConditionTracker; import com.android.launcher3.util.TraceHelper; -import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.BaseSwipeUpHandler.Factory; +import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.SwipeSharedState; @@ -81,12 +82,13 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3; private final RecentsAnimationDeviceState mDeviceState; + private final GestureState mGestureState; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final RunningTaskInfo mRunningTask; private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; private final SysUINavigationMode.Mode mMode; - private final ActivityControlHelper mActivityControlHelper; + private final BaseActivityInterface mActivityInterface; private final BaseSwipeUpHandler.Factory mHandlerFactory; @@ -126,20 +128,19 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private int mLogId; public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, - RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget, - Consumer onCompleteCallback, + GestureState gestureState, RunningTaskInfo runningTaskInfo, + boolean isDeferredDownTarget, Consumer onCompleteCallback, SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, - boolean disableHorizontalSwipe, ActivityControlHelper activityControlHelper, - Factory handlerFactory, int logId) { + boolean disableHorizontalSwipe, Factory handlerFactory, int logId) { super(base); mLogId = logId; - mDeviceState = deviceState; + mGestureState = gestureState; mMainThreadHandler = new Handler(Looper.getMainLooper()); mRunningTask = runningTaskInfo; mMode = SysUINavigationMode.getMode(base); mHandlerFactory = handlerFactory; - mActivityControlHelper = activityControlHelper; + mActivityInterface = mGestureState.getActivityInterface(); mMotionPauseDetector = new MotionPauseDetector(base); mMotionPauseMinDisplacement = base.getResources().getDimension( @@ -318,7 +319,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } mInputMonitorCompat.pilferPointers(); - mActivityControlHelper.closeOverlay(); + mActivityInterface.closeOverlay(); ActivityManagerWrapper.getInstance().closeSystemWindows( CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); @@ -331,8 +332,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC ActiveGestureLog.INSTANCE.addLog("startRecentsAnimation"); RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener(); - final BaseSwipeUpHandler handler = mHandlerFactory.newHandler(mRunningTask, touchTimeMs, - listenerSet != null, isLikelyToStartNewTask); + final BaseSwipeUpHandler handler = mHandlerFactory.newHandler(mGestureState, mRunningTask, + touchTimeMs, listenerSet != null, isLikelyToStartNewTask); mInteractionHandler = handler; handler.setGestureEndCallback(this::onInteractionGestureFinished); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index b09a5ac1c1..c19754fa56 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -26,7 +26,8 @@ import androidx.annotation.Nullable; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.Utilities; import com.android.launcher3.views.BaseDragLayer; -import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.BaseActivityInterface; +import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -41,7 +42,7 @@ public class OverviewInputConsumer implements InputConsumer { private final T mActivity; - private final ActivityControlHelper mActivityControlHelper; + private final BaseActivityInterface mActivityInterface; private final BaseDragLayer mTarget; private final InputMonitorCompat mInputMonitor; @@ -52,13 +53,12 @@ public class OverviewInputConsumer private final boolean mStartingInActivityBounds; private boolean mTargetHandledTouch; - public OverviewInputConsumer(T activity, @Nullable InputMonitorCompat inputMonitor, - boolean startingInActivityBounds, - ActivityControlHelper activityControlHelper) { + public OverviewInputConsumer(GestureState gestureState, T activity, + @Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) { mActivity = activity; mInputMonitor = inputMonitor; mStartingInActivityBounds = startingInActivityBounds; - mActivityControlHelper = activityControlHelper; + mActivityInterface = gestureState.getActivityInterface(); mTarget = activity.getDragLayer(); if (startingInActivityBounds) { @@ -100,7 +100,7 @@ public class OverviewInputConsumer if (!mTargetHandledTouch && handled) { mTargetHandledTouch = true; if (!mStartingInActivityBounds) { - mActivityControlHelper.closeOverlay(); + mActivityInterface.closeOverlay(); ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); ActiveGestureLog.INSTANCE.addLog("startQuickstep"); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java index c2560946c3..50069ea05c 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -35,8 +35,9 @@ import com.android.launcher3.Utilities; import com.android.launcher3.logging.StatsLogUtils; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; -import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.InputConsumer; +import com.android.quickstep.GestureState; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.NavBarPosition; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -50,17 +51,17 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { private final float mSquaredTouchSlop; private final Context mContext; private final NavBarPosition mNavBarPosition; - private final ActivityControlHelper mActivityControlHelper; + private final BaseActivityInterface mActivityInterface; private boolean mInterceptedTouch; private VelocityTracker mVelocityTracker; - public OverviewWithoutFocusInputConsumer(Context context, InputMonitorCompat inputMonitor, - ActivityControlHelper activityControlHelper, boolean disableHorizontalSwipe) { + public OverviewWithoutFocusInputConsumer(Context context, GestureState gestureState, + InputMonitorCompat inputMonitor, boolean disableHorizontalSwipe) { mInputMonitor = inputMonitor; mDisableHorizontalSwipe = disableHorizontalSwipe; mContext = context; - mActivityControlHelper = activityControlHelper; + mActivityInterface = gestureState.getActivityInterface(); mSquaredTouchSlop = Utilities.squaredTouchSlop(context); mNavBarPosition = new NavBarPosition(context); @@ -149,7 +150,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { } if (triggerQuickstep) { - mActivityControlHelper.closeOverlay(); + mActivityInterface.closeOverlay(); ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); ActiveGestureLog.INSTANCE.addLog("startQuickstep"); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java index ea80a383bd..97ca730402 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java @@ -35,7 +35,7 @@ import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; -import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.InputMonitorCompat; @@ -73,15 +73,16 @@ public class QuickCaptureInputConsumer private RecentsView mRecentsView; - public QuickCaptureInputConsumer(Context context, InputConsumer delegate, - InputMonitorCompat inputMonitor, ActivityControlHelper activityControlHelper) { + public QuickCaptureInputConsumer(Context context, GestureState gestureState, + InputConsumer delegate, InputMonitorCompat inputMonitor) { super(delegate, inputMonitor); mContext = context; float slop = ViewConfiguration.get(context).getScaledTouchSlop(); mSquaredSlop = slop * slop; - activityControlHelper.createActivityInitListener(this::onActivityInit).register(); + gestureState.getActivityInterface().createActivityInitListener(this::onActivityInit) + .register(); } @Override @@ -89,7 +90,7 @@ public class QuickCaptureInputConsumer return TYPE_QUICK_CAPTURE | mDelegate.getType(); } - private boolean onActivityInit(final T activity, Boolean alreadyOnHome) { + private boolean onActivityInit(final BaseDraggingActivity activity, Boolean alreadyOnHome) { mRecentsView = activity.getOverviewPanel(); return true; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java index d8b1bfdcfd..d5ed321e08 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java @@ -21,7 +21,7 @@ import android.view.MotionEvent; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; -import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.SystemUiProxy; @@ -38,14 +38,15 @@ public class ScreenPinnedInputConsumer implements InputConsumer { private float mTouchDownY; - public ScreenPinnedInputConsumer(Context context, ActivityControlHelper activityControl) { + public ScreenPinnedInputConsumer(Context context, GestureState gestureState) { mMotionPauseMinDisplacement = context.getResources().getDimension( R.dimen.motion_pause_detector_min_displacement_from_app); mMotionPauseDetector = new MotionPauseDetector(context, true /* makePauseHarderToTrigger*/); mMotionPauseDetector.setOnMotionPauseListener(isPaused -> { if (isPaused) { SystemUiProxy.INSTANCE.get(context).stopScreenPinning(); - BaseDraggingActivity launcherActivity = activityControl.getCreatedActivity(); + BaseDraggingActivity launcherActivity = gestureState.getActivityInterface() + .getCreatedActivity(); if (launcherActivity != null) { launcherActivity.getRootView().performHapticFeedback( HapticFeedbackConstants.LONG_PRESS, diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java similarity index 97% rename from quickstep/src/com/android/quickstep/ActivityControlHelper.java rename to quickstep/src/com/android/quickstep/BaseActivityInterface.java index 382232cda2..409bec6c70 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -42,7 +42,7 @@ import java.util.function.Consumer; * Utility class which abstracts out the logical differences between Launcher and RecentsActivity. */ @TargetApi(Build.VERSION_CODES.P) -public interface ActivityControlHelper { +public interface BaseActivityInterface { void onTransitionCancelled(T activity, boolean activityVisible); @@ -112,7 +112,7 @@ public interface ActivityControlHelper { default void onRemoteAnimationReceived(RemoteAnimationTargets targets) { } - void createActivityController(long transitionLength); + void createActivityInterface(long transitionLength); default void adjustActivityControllerInterpolators() { } diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java new file mode 100644 index 0000000000..de64227c26 --- /dev/null +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -0,0 +1,36 @@ +/* + * 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.quickstep; + +import com.android.launcher3.BaseDraggingActivity; + +/** + * Manages the state for an active system gesture, listens for events from the system and Launcher, + * and fires events when the states change. + */ +public class GestureState { + + // Needed to interact with the current activity + private BaseActivityInterface mActivityInterface; + + public GestureState(BaseActivityInterface activityInterface) { + mActivityInterface = activityInterface; + } + + public BaseActivityInterface getActivityInterface() { + return mActivityInterface; + } +} diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java index 331183a512..73b78db6cd 100644 --- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java +++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java @@ -62,7 +62,7 @@ public final class OverviewComponentObserver { private final Intent mFallbackIntent; private final SparseIntArray mConfigChangesMap = new SparseIntArray(); private String mUpdateRegisteredPackage; - private ActivityControlHelper mActivityControlHelper; + private BaseActivityInterface mActivityInterface; private Intent mOverviewIntent; private boolean mIsHomeAndOverviewSame; private boolean mIsDefaultHome; @@ -106,7 +106,7 @@ public final class OverviewComponentObserver { } /** - * Update overview intent and {@link ActivityControlHelper} based off the current launcher home + * Update overview intent and {@link BaseActivityInterface} based off the current launcher home * component. */ private void updateOverviewTargets() { @@ -119,13 +119,13 @@ public final class OverviewComponentObserver { // Set assistant visibility to 0 from launcher's perspective, ensures any elements that // launcher made invisible become visible again before the new activity control helper // becomes active. - if (mActivityControlHelper != null) { - mActivityControlHelper.onAssistantVisibilityChanged(0.f); + if (mActivityInterface != null) { + mActivityInterface.onAssistantVisibilityChanged(0.f); } if (!mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) { // User default home is same as out home app. Use Overview integrated in Launcher. - mActivityControlHelper = new LauncherActivityControllerHelper(); + mActivityInterface = new LauncherActivityInterface(); mIsHomeAndOverviewSame = true; mOverviewIntent = mMyHomeIntent; mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent()); @@ -138,7 +138,7 @@ public final class OverviewComponentObserver { } else { // The default home app is a different launcher. Use the fallback Overview instead. - mActivityControlHelper = new FallbackActivityControllerHelper(); + mActivityInterface = new FallbackActivityInterface(); mIsHomeAndOverviewSame = false; mOverviewIntent = mFallbackIntent; mCurrentHomeIntent.setComponent(defaultHome); @@ -230,7 +230,7 @@ public final class OverviewComponentObserver { * * @return the current activity control helper */ - public ActivityControlHelper getActivityControlHelper() { - return mActivityControlHelper; + public BaseActivityInterface getActivityInterface() { + return mActivityInterface; } } From c039634c25140173bcd81a243fa3ac5489b6b5d8 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 10 Oct 2019 16:49:18 -0700 Subject: [PATCH 098/109] Workaround for failing test & fix scrolling in tests - Workaround issue where instrumentation will fail to finish an activity causing the activity to linger longer than expected (leading to issues with ordering of static resources like the app widget host registration) - Fix calculation for scrolling the screen, the previous calculation would result in the gesture starting at the left gesture margin due to rounding which can trigger a back action instead of the desired scroll Bug: 142351228 Change-Id: I34bdb471030518d2b983cac2badd4d8b0e7d571b --- .../quickstep/ViewInflationDuringSwipeUp.java | 8 +++++++ .../tapl/LauncherInstrumentation.java | 24 +++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java index 67261796f8..8b7c7b793f 100644 --- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java +++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java @@ -89,6 +89,14 @@ public class ViewInflationDuringSwipeUp extends AbstractQuickStepTest { @Before public void setUp() throws Exception { super.setUp(); + + // Workaround for b/142351228, when there are no activities, the system may not destroy the + // activity correctly for activities under instrumentation, which can leave two concurrent + // activities, which changes the order in which the activities are cleaned up (overlapping + // stop and start) leading to all sort of issues. To workaround this, ensure that the test + // is started only after starting another app. + startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); + TaplTestsLauncher3.initialize(this); mResolver = mTargetContext.getContentResolver(); diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 41a5b49be7..3248d6ada0 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -822,34 +822,26 @@ public final class LauncherInstrumentation { switch (direction) { case UP: { startX = endX = rect.centerX(); - final int vertCenter = rect.centerY(); - final float halfGestureHeight = rect.height() / 2.0f; - startY = (int) (vertCenter - halfGestureHeight) + 1; - endY = (int) (vertCenter + halfGestureHeight); + startY = rect.top + 1; + endY = rect.bottom; } break; case DOWN: { startX = endX = rect.centerX(); - final int vertCenter = rect.centerY(); - final float halfGestureHeight = rect.height() / 2.0f; - startY = (int) (vertCenter + halfGestureHeight) - 1; - endY = (int) (vertCenter - halfGestureHeight); + startY = rect.bottom - 1; + endY = rect.top; } break; case LEFT: { startY = endY = rect.centerY(); - final int horizCenter = rect.centerX(); - final float halfGestureWidth = rect.width() / 2.0f; - startX = (int) (horizCenter - halfGestureWidth) + 1; - endX = (int) (horizCenter + halfGestureWidth); + startX = rect.left + 1; + endX = rect.right; } break; case RIGHT: { startY = endY = rect.centerY(); - final int horizCenter = rect.centerX(); - final float halfGestureWidth = rect.width() / 2.0f; - startX = (int) (horizCenter + halfGestureWidth) - 1; - endX = (int) (horizCenter - halfGestureWidth); + startX = rect.right - 1; + endX = rect.left; } break; default: From 76b2775eee4627d974c6286ae1091e9e591c00ab Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 11 Oct 2019 08:11:57 -0700 Subject: [PATCH 099/109] Import translations. DO NOT MERGE Change-Id: I9dc5e28b5460a89b6b43f114aa4462f65f834d50 Auto-generated-cl: translation import --- .../res/values-ar/strings.xml | 2 +- .../res/values-en-rCA/strings.xml | 25 +++ .../res/values-en-rXC/strings.xml | 25 +++ quickstep/res/values-en-rCA/strings.xml | 37 +++++ quickstep/res/values-en-rXC/strings.xml | 37 +++++ res/values-bn/strings.xml | 2 +- res/values-en-rCA/strings.xml | 143 ++++++++++++++++++ res/values-en-rXC/strings.xml | 143 ++++++++++++++++++ res/values-gu/strings.xml | 2 +- res/values-mk/strings.xml | 4 +- res/values-or/strings.xml | 2 +- res/values-ta/strings.xml | 2 +- 12 files changed, 417 insertions(+), 7 deletions(-) create mode 100644 SecondaryDisplayLauncher/res/values-en-rCA/strings.xml create mode 100644 SecondaryDisplayLauncher/res/values-en-rXC/strings.xml create mode 100644 quickstep/res/values-en-rCA/strings.xml create mode 100644 quickstep/res/values-en-rXC/strings.xml create mode 100644 res/values-en-rCA/strings.xml create mode 100644 res/values-en-rXC/strings.xml diff --git a/SecondaryDisplayLauncher/res/values-ar/strings.xml b/SecondaryDisplayLauncher/res/values-ar/strings.xml index ba81c118c2..aa34c7d166 100644 --- a/SecondaryDisplayLauncher/res/values-ar/strings.xml +++ b/SecondaryDisplayLauncher/res/values-ar/strings.xml @@ -21,5 +21,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "تعذَّر تشغيل النشاط." "إضافة اختصار التطبيق" - "تعيين الخلفية" + "ضبط الخلفية" diff --git a/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml b/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..8d8c419b2d --- /dev/null +++ b/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Couldn\'t launch the activity" + "Add app shortcut" + "Set wallpaper" + diff --git a/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml b/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..da69193348 --- /dev/null +++ b/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎Couldn\'t launch the activity‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎Add app shortcut‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎Set wallpaper‎‏‎‎‏‎" + diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..2d1418e5f4 --- /dev/null +++ b/quickstep/res/values-en-rCA/strings.xml @@ -0,0 +1,37 @@ + + + + + "Split screen" + "Pin" + "Freeform" + "Overview" + "No recent items" + "Close" + "App usage settings" + "Clear all" + "Recent apps" + "%1$s, %2$s" + "< 1 minute" + "%1$s left today" + "App suggestions" + "All apps" + "Your predicted apps" + diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..bb186db26d --- /dev/null +++ b/quickstep/res/values-en-rXC/strings.xml @@ -0,0 +1,37 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎Split screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎Pin‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎Freeform‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎Overview‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎No recent items‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎Close‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎App usage settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎Clear all‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎Recent apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‎< 1 minute‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ left today‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎App suggestions‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎All apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎Your predicted apps‎‏‎‎‏‎" + diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 775885caac..a67674ca52 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -93,7 +93,7 @@ "সেটিংস পরিবর্তন করুন" "বিজ্ঞপ্তির ডট দেখুন" "হোম স্ক্রিনে আইকন যোগ করুন" - "নতুন অ্যাপ্লিকেশানগুলির জন্যে" + "নতুন অ্যাপের জন্য" "অজানা" "সরান" "সার্চ" diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..0c48b5d2cb --- /dev/null +++ b/res/values-en-rCA/strings.xml @@ -0,0 +1,143 @@ + + + + + "Launcher3" + + "Work" + "App isn\'t installed." + "App isn\'t available" + "Downloaded app disabled in Safe mode" + "Widgets disabled in Safe mode" + "Shortcut isn\'t available" + "Home screen" + "Customised actions" + "Touch & hold to pick up a widget." + "Double-tap & hold to pick up a widget or use customised actions." + "%1$d × %2$d" + "%1$d wide by %2$d high" + "Touch & hold to place manually" + "Add automatically" + "Search apps" + "Loading apps…" + "No apps found matching \'%1$s\'" + "Search for more apps" + "App" + "Notifications" + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." + "No more room on this Home screen." + "No more room in the Favourites tray" + "Apps list" + "Personal apps list" + "Work apps list" + "Home" + "Remove" + "Uninstall" + "App info" + "Install" + "install shortcuts" + "Allows an app to add shortcuts without user intervention." + "read Home settings and shortcuts" + "Allows the app to read the settings and shortcuts in Home." + "write Home settings and shortcuts" + "Allows the app to change the settings and shortcuts in Home." + "%1$s is not allowed to make phone calls" + "Problem loading widget" + "Setup" + "This is a system app and can\'t be uninstalled." + "Unnamed Folder" + "Disabled %1$s" + + %1$s, has %2$d notifications + %1$s, has %2$d notification + + "Page %1$d of %2$d" + "Home screen %1$d of %2$d" + "New home screen page" + "Folder opened, %1$d by %2$d" + "Tap to close folder" + "Tap to save rename" + "Folder closed" + "Folder renamed to %1$s" + "Folder: %1$s" + "Widgets" + "Wallpapers" + "Styles & wallpapers" + "Home settings" + "Disabled by your admin" + "Allow Home screen rotation" + "When phone is rotated" + "Notification dots" + "On" + "Off" + "Notification access needed" + "To show Notification Dots, turn on app notifications for %1$s" + "Change settings" + "Show notification dots" + "Add icon to Home screen" + "For new apps" + "Unknown" + "Remove" + "Search" + "This app is not installed" + "The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually." + "%1$s downloading, %2$s complete" + "%1$s waiting to install" + "%1$s widgets" + "Widgets list" + "Widgets list closed" + "Add to Home screen" + "Move item here" + "Item added to home screen" + "Item removed" + "Undo" + "Move item" + "Move to row %1$s column %2$s" + "Move to position %1$s" + "Move to favourites position %1$s" + "Item moved" + "Add to folder: %1$s" + "Add to folder with %1$s" + "Item added to folder" + "Create folder with: %1$s" + "Folder created" + "Move to Home screen" + "Re-size" + "Increase width" + "Increase height" + "Decrease width" + "Decrease height" + "Widget re-sized to width %1$s height %2$s" + "Short cuts" + "Shortcuts and notifications" + "Dismiss" + "Notification dismissed" + "Personal" + "Work" + "Work profile" + "Find work apps here" + "Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access." + "Managed by your organisation" + "Notifications and apps are off" + "Close" + "Closed" + "Failed: %1$s" + diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..3c65f54523 --- /dev/null +++ b/res/values-en-rXC/strings.xml @@ -0,0 +1,143 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎Launcher3‎‏‎‎‏‎" + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎Work‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎App isn\'t installed.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎App isn\'t available‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎Downloaded app disabled in Safe mode‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎Widgets disabled in Safe mode‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎Shortcut isn\'t available‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎Custom actions‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎Touch & hold to pick up a widget.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎Double-tap & hold to pick up a widget or use custom actions.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎%1$d × %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎%1$d wide by %2$d high‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎Touch & hold to place manually‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎Add automatically‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎Search apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎Loading apps…‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎No apps found matching \"‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎Search for more apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎App‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎Notifications‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎Touch & hold to pick up a shortcut.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎Double-tap & hold to pick up a shortcut or use custom actions.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎No more room on this Home screen.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎No more room in the Favorites tray‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎Apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎Personal apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎Work apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎Home‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎Remove‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎Uninstall‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎App info‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎Install‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎install shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎Allows an app to add shortcuts without user intervention.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎read Home settings and shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎Allows the app to read the settings and shortcuts in Home.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‎write Home settings and shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‎Allows the app to change the settings and shortcuts in Home.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ is not allowed to make phone calls‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎Problem loading widget‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎Setup‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‎‎This is a system app and can\'t be uninstalled.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎Unnamed Folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎Disabled ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, has ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎ notifications‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, has ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎ notification‎‏‎‎‏‎ + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‎Page %1$d of %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎Home screen %1$d of %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎New home screen page‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‎Folder opened, ‎‏‎‎‏‏‎%1$d‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎Tap to close folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎Tap to save rename‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎Folder closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎Folder renamed to ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎Folder: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎Widgets‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎Wallpapers‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎Styles & wallpapers‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎Home settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎Disabled by your admin‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎Allow Home screen rotation‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎When phone is rotated‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎Notification dots‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎On‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎Off‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎Notification access needed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎To show Notification Dots, turn on app notifications for ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎Change settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎Show notification dots‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‎Add icon to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎For new apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎Unknown‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎Remove‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎Search‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎This app is not installed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ downloading, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ complete‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ waiting to install‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ widgets‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎Widgets list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎Widgets list closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎Add to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎Move item here‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎Item added to home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎Item removed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎Undo‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎Move item‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎Move to row ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ column ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎Move to position ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎Move to favorites position ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎Item moved‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎Add to folder: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎Add to folder with ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎Item added to folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎Create folder with: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎Folder created‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎Move to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎Resize‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎Increase width‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎Increase height‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎Decrease width‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎Decrease height‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎Widget resized to width ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ height ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎Shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎Shortcuts and notifications‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎Dismiss‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎Notification dismissed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎Personal‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎Work‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎Work profile‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎Find work apps here‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎Each work app has a badge and is kept secure by your organization. Move apps to your Home screen for easier access.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎Managed by your organization‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎Notifications and apps are off‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎Close‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‎Closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎Failed: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index 7def3ace9a..9fed4808ee 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -81,7 +81,7 @@ "વિજેટ્સ" "વૉલપેપર્સ" "શૈલીઓ અને વૉલપેપર" - "હોમ સેટિંગ્સ" + "હોમ સેટિંગ" "તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ" "હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો" "જ્યારે ફોન ફેરવવામાં આવે ત્યારે" diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 9550a5f0f5..49df044600 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -81,9 +81,9 @@ "Виџети" "Тапети" "Стилови и тапети" - "Поставки за Home" + "Поставки за почетен екран" "Оневозможено од администраторот" - "Дозволете ротација на Почетниот екран" + "Дозволете ротација на почетниот екран" "Кога телефонот се ротира" "Точки за известување" "Вклучено" diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index 4ddc903474..ab42923019 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -85,7 +85,7 @@ "ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି" "ହୋମ୍‌ ସ୍କ୍ରୀନ୍ ବୁଲାଇବା ଅନୁମତି ଦିଅନ୍ତୁ" "ଯେତେବେଳେ ଫୋନକୁ ବୁଲାଯାଇଥାଏ" - "ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁଗୁଡ଼ିକ" + "ବିଜ୍ଞପ୍ତି ଡଟ୍ସ" "ଚାଲୁ କରନ୍ତୁ" "ବନ୍ଦ କରନ୍ତୁ" "ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ୍‌ ଆବଶ୍ୟକ ଅଟେ" diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 2c0dcc45c9..e73cb89857 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -37,7 +37,7 @@ "தானாகவே சேர்" "பயன்பாடுகளில் தேடுக" "ஆப்ஸை ஏற்றுகிறது…" - "\"%1$s\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை" + "\"%1$s\" உடன் பொருந்தும் ஆப்ஸ் இல்லை" "கூடுதல் பயன்பாடுகளைத் தேடு" "ஆப்ஸ்" "அறிவிப்புகள்" From e72b993b912b61f53bdb00d5e36b346016887e8b Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 11 Oct 2019 08:15:45 -0700 Subject: [PATCH 100/109] Import translations. DO NOT MERGE Change-Id: Ie268b67529ed9728f79745402d430d007f0f3286 Auto-generated-cl: translation import --- .../res/values-ar/strings.xml | 2 +- .../res/values-en-rCA/strings.xml | 25 +++ .../res/values-en-rXC/strings.xml | 25 +++ quickstep/res/values-en-rCA/strings.xml | 37 +++++ quickstep/res/values-en-rXC/strings.xml | 37 +++++ res/values-bn/strings.xml | 2 +- res/values-en-rCA/strings.xml | 143 ++++++++++++++++++ res/values-en-rXC/strings.xml | 143 ++++++++++++++++++ res/values-fr/strings.xml | 2 +- res/values-gu/strings.xml | 2 +- res/values-hy/strings.xml | 2 +- res/values-mk/strings.xml | 4 +- res/values-mr/strings.xml | 2 +- res/values-or/strings.xml | 2 +- res/values-sq/strings.xml | 4 +- res/values-ta/strings.xml | 6 +- res/values-te/strings.xml | 2 +- res/values-vi/strings.xml | 2 +- 18 files changed, 426 insertions(+), 16 deletions(-) create mode 100644 SecondaryDisplayLauncher/res/values-en-rCA/strings.xml create mode 100644 SecondaryDisplayLauncher/res/values-en-rXC/strings.xml create mode 100644 quickstep/res/values-en-rCA/strings.xml create mode 100644 quickstep/res/values-en-rXC/strings.xml create mode 100644 res/values-en-rCA/strings.xml create mode 100644 res/values-en-rXC/strings.xml diff --git a/SecondaryDisplayLauncher/res/values-ar/strings.xml b/SecondaryDisplayLauncher/res/values-ar/strings.xml index ba81c118c2..aa34c7d166 100644 --- a/SecondaryDisplayLauncher/res/values-ar/strings.xml +++ b/SecondaryDisplayLauncher/res/values-ar/strings.xml @@ -21,5 +21,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "تعذَّر تشغيل النشاط." "إضافة اختصار التطبيق" - "تعيين الخلفية" + "ضبط الخلفية" diff --git a/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml b/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..8d8c419b2d --- /dev/null +++ b/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Couldn\'t launch the activity" + "Add app shortcut" + "Set wallpaper" + diff --git a/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml b/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..da69193348 --- /dev/null +++ b/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎Couldn\'t launch the activity‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎Add app shortcut‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎Set wallpaper‎‏‎‎‏‎" + diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..2d1418e5f4 --- /dev/null +++ b/quickstep/res/values-en-rCA/strings.xml @@ -0,0 +1,37 @@ + + + + + "Split screen" + "Pin" + "Freeform" + "Overview" + "No recent items" + "Close" + "App usage settings" + "Clear all" + "Recent apps" + "%1$s, %2$s" + "< 1 minute" + "%1$s left today" + "App suggestions" + "All apps" + "Your predicted apps" + diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..bb186db26d --- /dev/null +++ b/quickstep/res/values-en-rXC/strings.xml @@ -0,0 +1,37 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎Split screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎Pin‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎Freeform‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎Overview‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎No recent items‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎Close‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎App usage settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎Clear all‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎Recent apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‎< 1 minute‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ left today‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎App suggestions‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎All apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎Your predicted apps‎‏‎‎‏‎" + diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 775885caac..a67674ca52 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -93,7 +93,7 @@ "সেটিংস পরিবর্তন করুন" "বিজ্ঞপ্তির ডট দেখুন" "হোম স্ক্রিনে আইকন যোগ করুন" - "নতুন অ্যাপ্লিকেশানগুলির জন্যে" + "নতুন অ্যাপের জন্য" "অজানা" "সরান" "সার্চ" diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..0c48b5d2cb --- /dev/null +++ b/res/values-en-rCA/strings.xml @@ -0,0 +1,143 @@ + + + + + "Launcher3" + + "Work" + "App isn\'t installed." + "App isn\'t available" + "Downloaded app disabled in Safe mode" + "Widgets disabled in Safe mode" + "Shortcut isn\'t available" + "Home screen" + "Customised actions" + "Touch & hold to pick up a widget." + "Double-tap & hold to pick up a widget or use customised actions." + "%1$d × %2$d" + "%1$d wide by %2$d high" + "Touch & hold to place manually" + "Add automatically" + "Search apps" + "Loading apps…" + "No apps found matching \'%1$s\'" + "Search for more apps" + "App" + "Notifications" + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." + "No more room on this Home screen." + "No more room in the Favourites tray" + "Apps list" + "Personal apps list" + "Work apps list" + "Home" + "Remove" + "Uninstall" + "App info" + "Install" + "install shortcuts" + "Allows an app to add shortcuts without user intervention." + "read Home settings and shortcuts" + "Allows the app to read the settings and shortcuts in Home." + "write Home settings and shortcuts" + "Allows the app to change the settings and shortcuts in Home." + "%1$s is not allowed to make phone calls" + "Problem loading widget" + "Setup" + "This is a system app and can\'t be uninstalled." + "Unnamed Folder" + "Disabled %1$s" + + %1$s, has %2$d notifications + %1$s, has %2$d notification + + "Page %1$d of %2$d" + "Home screen %1$d of %2$d" + "New home screen page" + "Folder opened, %1$d by %2$d" + "Tap to close folder" + "Tap to save rename" + "Folder closed" + "Folder renamed to %1$s" + "Folder: %1$s" + "Widgets" + "Wallpapers" + "Styles & wallpapers" + "Home settings" + "Disabled by your admin" + "Allow Home screen rotation" + "When phone is rotated" + "Notification dots" + "On" + "Off" + "Notification access needed" + "To show Notification Dots, turn on app notifications for %1$s" + "Change settings" + "Show notification dots" + "Add icon to Home screen" + "For new apps" + "Unknown" + "Remove" + "Search" + "This app is not installed" + "The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually." + "%1$s downloading, %2$s complete" + "%1$s waiting to install" + "%1$s widgets" + "Widgets list" + "Widgets list closed" + "Add to Home screen" + "Move item here" + "Item added to home screen" + "Item removed" + "Undo" + "Move item" + "Move to row %1$s column %2$s" + "Move to position %1$s" + "Move to favourites position %1$s" + "Item moved" + "Add to folder: %1$s" + "Add to folder with %1$s" + "Item added to folder" + "Create folder with: %1$s" + "Folder created" + "Move to Home screen" + "Re-size" + "Increase width" + "Increase height" + "Decrease width" + "Decrease height" + "Widget re-sized to width %1$s height %2$s" + "Short cuts" + "Shortcuts and notifications" + "Dismiss" + "Notification dismissed" + "Personal" + "Work" + "Work profile" + "Find work apps here" + "Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access." + "Managed by your organisation" + "Notifications and apps are off" + "Close" + "Closed" + "Failed: %1$s" + diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..3c65f54523 --- /dev/null +++ b/res/values-en-rXC/strings.xml @@ -0,0 +1,143 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎Launcher3‎‏‎‎‏‎" + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎Work‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎App isn\'t installed.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎App isn\'t available‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎Downloaded app disabled in Safe mode‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎Widgets disabled in Safe mode‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎Shortcut isn\'t available‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎Custom actions‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎Touch & hold to pick up a widget.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎Double-tap & hold to pick up a widget or use custom actions.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎%1$d × %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎%1$d wide by %2$d high‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎Touch & hold to place manually‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎Add automatically‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎Search apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎Loading apps…‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎No apps found matching \"‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎Search for more apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎App‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎Notifications‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎Touch & hold to pick up a shortcut.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎Double-tap & hold to pick up a shortcut or use custom actions.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎No more room on this Home screen.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎No more room in the Favorites tray‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎Apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎Personal apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎Work apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎Home‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎Remove‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎Uninstall‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎App info‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎Install‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎install shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎Allows an app to add shortcuts without user intervention.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎read Home settings and shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎Allows the app to read the settings and shortcuts in Home.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‎write Home settings and shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‎Allows the app to change the settings and shortcuts in Home.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ is not allowed to make phone calls‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎Problem loading widget‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎Setup‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‎‎This is a system app and can\'t be uninstalled.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎Unnamed Folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎Disabled ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, has ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎ notifications‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, has ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎ notification‎‏‎‎‏‎ + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‎Page %1$d of %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎Home screen %1$d of %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎New home screen page‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‎Folder opened, ‎‏‎‎‏‏‎%1$d‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎Tap to close folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎Tap to save rename‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎Folder closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎Folder renamed to ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎Folder: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎Widgets‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎Wallpapers‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎Styles & wallpapers‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎Home settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎Disabled by your admin‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎Allow Home screen rotation‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎When phone is rotated‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎Notification dots‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎On‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎Off‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎Notification access needed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎To show Notification Dots, turn on app notifications for ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎Change settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎Show notification dots‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‎Add icon to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎For new apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎Unknown‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎Remove‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎Search‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎This app is not installed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ downloading, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ complete‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ waiting to install‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ widgets‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎Widgets list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎Widgets list closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎Add to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎Move item here‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎Item added to home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎Item removed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎Undo‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎Move item‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎Move to row ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ column ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎Move to position ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎Move to favorites position ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎Item moved‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎Add to folder: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎Add to folder with ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎Item added to folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎Create folder with: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎Folder created‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎Move to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎Resize‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎Increase width‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎Increase height‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎Decrease width‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎Decrease height‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎Widget resized to width ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ height ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎Shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎Shortcuts and notifications‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎Dismiss‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎Notification dismissed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎Personal‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎Work‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎Work profile‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎Find work apps here‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎Each work app has a badge and is kept secure by your organization. Move apps to your Home screen for easier access.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎Managed by your organization‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎Notifications and apps are off‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎Close‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‎Closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎Failed: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 7b4bcb1d82..c04c951b7e 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -136,7 +136,7 @@ "Retrouvez ici vos applications professionnelles" "Les applications professionnelles sont accompagnées d\'un badge et sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement." "Géré par votre organisation" - "Les notifications et les applications sont désactivées" + "Notifications et applications désactivées" "Fermer" "Fermé" "Échec : %1$s" diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index 7def3ace9a..9fed4808ee 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -81,7 +81,7 @@ "વિજેટ્સ" "વૉલપેપર્સ" "શૈલીઓ અને વૉલપેપર" - "હોમ સેટિંગ્સ" + "હોમ સેટિંગ" "તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ" "હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો" "જ્યારે ફોન ફેરવવામાં આવે ત્યારે" diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml index fbb657ebd9..c81d55a908 100644 --- a/res/values-hy/strings.xml +++ b/res/values-hy/strings.xml @@ -87,7 +87,7 @@ "Հեռախոսը պտտելու դեպքում" "Ծանուցումների կետիկներ" "Միացված է" - "Անջատած է" + "Անջատված է" "Անհրաժեշտ է ծանուցման թույլտվություն" "Ծանուցումների կետիկները ցուցադրելու համար միացրեք ծանուցումները %1$s-ի համար" "Փոխել կարգավորումները" diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index 9550a5f0f5..49df044600 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -81,9 +81,9 @@ "Виџети" "Тапети" "Стилови и тапети" - "Поставки за Home" + "Поставки за почетен екран" "Оневозможено од администраторот" - "Дозволете ротација на Почетниот екран" + "Дозволете ротација на почетниот екран" "Кога телефонот се ротира" "Точки за известување" "Вклучено" diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml index 49e38982cd..3ae8f1ad15 100644 --- a/res/values-mr/strings.xml +++ b/res/values-mr/strings.xml @@ -83,7 +83,7 @@ "शैली आणि वॉलपेपर" "होम सेटिंग्‍ज" "आपल्या प्रशासकाने अक्षम केले" - "मुख्यस्क्रीन फिरविण्‍यास अनुमती द्या" + "मुख्य स्क्रीन फिरविण्‍यास अनुमती द्या" "फोन फिरविला जातो तेव्हा" "सूचना बिंदू" "सुरू" diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index 4ddc903474..ab42923019 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -85,7 +85,7 @@ "ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି" "ହୋମ୍‌ ସ୍କ୍ରୀନ୍ ବୁଲାଇବା ଅନୁମତି ଦିଅନ୍ତୁ" "ଯେତେବେଳେ ଫୋନକୁ ବୁଲାଯାଇଥାଏ" - "ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁଗୁଡ଼ିକ" + "ବିଜ୍ଞପ୍ତି ଡଟ୍ସ" "ଚାଲୁ କରନ୍ତୁ" "ବନ୍ଦ କରନ୍ତୁ" "ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ୍‌ ଆବଶ୍ୟକ ଅଟେ" diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml index 48ae26ed84..e25c1c11f5 100644 --- a/res/values-sq/strings.xml +++ b/res/values-sq/strings.xml @@ -41,8 +41,8 @@ "Kërko për më shumë aplikacione" "Aplikacioni" "Njoftimet" - "Prek dhe mbaj prekur për të zgjedhur një shkurtore." - "Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara." + "Prek dhe mbaj të shtypur për të zgjedhur një shkurtore." + "Prek dy herë dhe mbaj të shtypur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara." "Nuk ka më hapësirë në këtë ekran bazë." "Nuk ka më hapësirë në tabakanë \"Të preferuarat\"" "Lista e aplikacioneve" diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index c926bc185b..e73cb89857 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -36,8 +36,8 @@ "நீங்களே சேர்க்க, தொட்டுப் பிடித்திருக்கவும்" "தானாகவே சேர்" "பயன்பாடுகளில் தேடுக" - "பயன்பாடுகளை ஏற்றுகிறது…" - "\"%1$s\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை" + "ஆப்ஸை ஏற்றுகிறது…" + "\"%1$s\" உடன் பொருந்தும் ஆப்ஸ் இல்லை" "கூடுதல் பயன்பாடுகளைத் தேடு" "ஆப்ஸ்" "அறிவிப்புகள்" @@ -45,7 +45,7 @@ "ஷார்ட்கட்டைச் சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் (அ) தனிப்பயன் செயல்களைப் பயன்படுத்தவும்." "முகப்புத் திரையில் இடமில்லை." "பிடித்தவை ட்ரேயில் இடமில்லை" - "பயன்பாடுகளின் பட்டியல்" + "ஆப்ஸின் பட்டியல்" "தனிப்பட்ட ஆப்ஸ் பட்டியல்" "பணி ஆப்ஸ் பட்டியல்" "முகப்பு" diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index c8f70fe058..0d99e2b888 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -53,7 +53,7 @@ "అన్ఇన్‌స్టాల్ చేయి" "యాప్ సమాచారం" "ఇన్‌స్టాల్ చేయండి" - "సత్వరమార్గాలను ఇన్‌స్టాల్ చేయడం" + "షార్ట్‌కట్‌లను ఇన్‌స్టాల్ చేయడం" "వినియోగదారు ప్రమేయం లేకుండా సత్వరమార్గాలను జోడించడానికి అనువర్తనాన్ని అనుమతిస్తుంది." "హోమ్ సెట్టింగ్‌లు మరియు సత్వరమార్గాలను చదవడం" "హోమ్‌లో సెట్టింగ్‌లు మరియు సత్వరమార్గాలను చదవడానికి అనువర్తనాన్ని అనుమతిస్తుంది." diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 71decfca68..f3519a50ce 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -86,7 +86,7 @@ "Cho phép xoay Màn hình chính" "Khi xoay điện thoại" "Dấu chấm thông báo" - "Bật" + "Đang bật" "Tắt" "Cần quyền truy cập thông báo" "Để hiển thị Dấu chấm thông báo, hãy bật thông báo ứng dụng cho %1$s" From e2c21704ebcce1857fc2188ac379199f1d64f08c Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 11 Oct 2019 08:19:31 -0700 Subject: [PATCH 101/109] Import translations. DO NOT MERGE Change-Id: I2ce1448b6a7ee5cb455a2fc044336c37e03093aa Auto-generated-cl: translation import --- .../res/values-ar/strings.xml | 2 +- .../res/values-en-rCA/strings.xml | 25 +++ .../res/values-en-rXC/strings.xml | 25 +++ quickstep/res/values-en-rCA/strings.xml | 37 +++++ quickstep/res/values-en-rXC/strings.xml | 37 +++++ res/values-bn/strings.xml | 2 +- res/values-en-rCA/strings.xml | 142 ++++++++++++++++++ res/values-en-rXC/strings.xml | 142 ++++++++++++++++++ res/values-gu/strings.xml | 2 +- res/values-mk/strings.xml | 4 +- res/values-or/strings.xml | 2 +- res/values-ta/strings.xml | 2 +- 12 files changed, 415 insertions(+), 7 deletions(-) create mode 100644 SecondaryDisplayLauncher/res/values-en-rCA/strings.xml create mode 100644 SecondaryDisplayLauncher/res/values-en-rXC/strings.xml create mode 100644 quickstep/res/values-en-rCA/strings.xml create mode 100644 quickstep/res/values-en-rXC/strings.xml create mode 100644 res/values-en-rCA/strings.xml create mode 100644 res/values-en-rXC/strings.xml diff --git a/SecondaryDisplayLauncher/res/values-ar/strings.xml b/SecondaryDisplayLauncher/res/values-ar/strings.xml index ba81c118c2..aa34c7d166 100644 --- a/SecondaryDisplayLauncher/res/values-ar/strings.xml +++ b/SecondaryDisplayLauncher/res/values-ar/strings.xml @@ -21,5 +21,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "تعذَّر تشغيل النشاط." "إضافة اختصار التطبيق" - "تعيين الخلفية" + "ضبط الخلفية" diff --git a/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml b/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..8d8c419b2d --- /dev/null +++ b/SecondaryDisplayLauncher/res/values-en-rCA/strings.xml @@ -0,0 +1,25 @@ + + + + + "Couldn\'t launch the activity" + "Add app shortcut" + "Set wallpaper" + diff --git a/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml b/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..da69193348 --- /dev/null +++ b/SecondaryDisplayLauncher/res/values-en-rXC/strings.xml @@ -0,0 +1,25 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎Couldn\'t launch the activity‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎Add app shortcut‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎Set wallpaper‎‏‎‎‏‎" + diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..2d1418e5f4 --- /dev/null +++ b/quickstep/res/values-en-rCA/strings.xml @@ -0,0 +1,37 @@ + + + + + "Split screen" + "Pin" + "Freeform" + "Overview" + "No recent items" + "Close" + "App usage settings" + "Clear all" + "Recent apps" + "%1$s, %2$s" + "< 1 minute" + "%1$s left today" + "App suggestions" + "All apps" + "Your predicted apps" + diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..bb186db26d --- /dev/null +++ b/quickstep/res/values-en-rXC/strings.xml @@ -0,0 +1,37 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‎‎Split screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎Pin‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎Freeform‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎Overview‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎No recent items‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎Close‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎App usage settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎Clear all‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎Recent apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‎< 1 minute‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ left today‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎App suggestions‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎All apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎Your predicted apps‎‏‎‎‏‎" + diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml index 09608b5426..0a72632fd6 100644 --- a/res/values-bn/strings.xml +++ b/res/values-bn/strings.xml @@ -92,7 +92,7 @@ "সেটিংস পরিবর্তন করুন" "বিজ্ঞপ্তির ডট দেখুন" "হোম স্ক্রিনে আইকন যোগ করুন" - "নতুন অ্যাপ্লিকেশানগুলির জন্যে" + "নতুন অ্যাপের জন্য" "অজানা" "সরান" "সার্চ" diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml new file mode 100644 index 0000000000..7adc2187ec --- /dev/null +++ b/res/values-en-rCA/strings.xml @@ -0,0 +1,142 @@ + + + + + "Launcher3" + "Work" + "App isn\'t installed." + "App isn\'t available" + "Downloaded app disabled in Safe mode" + "Widgets disabled in Safe mode" + "Shortcut isn\'t available" + "Home screen" + "Customised actions" + "Touch & hold to pick up a widget." + "Double-tap & hold to pick up a widget or use customised actions." + "%1$d × %2$d" + "%1$d wide by %2$d high" + "Touch & hold to place manually" + "Add automatically" + "Search apps" + "Loading apps…" + "No apps found matching \'%1$s\'" + "Search for more apps" + "App" + "Notifications" + "Touch & hold to pick up a shortcut." + "Double-tap & hold to pick up a shortcut or use custom actions." + "No more room on this Home screen." + "No more room in the Favourites tray" + "Apps list" + "Personal apps list" + "Work apps list" + "Home" + "Remove" + "Uninstall" + "App info" + "Install" + "install shortcuts" + "Allows an app to add shortcuts without user intervention." + "read Home settings and shortcuts" + "Allows the app to read the settings and shortcuts in Home." + "write Home settings and shortcuts" + "Allows the app to change the settings and shortcuts in Home." + "%1$s is not allowed to make phone calls" + "Problem loading widget" + "Setup" + "This is a system app and can\'t be uninstalled." + "Unnamed Folder" + "Disabled %1$s" + + %1$s, has %2$d notifications + %1$s, has %2$d notification + + "Page %1$d of %2$d" + "Home screen %1$d of %2$d" + "New home screen page" + "Folder opened, %1$d by %2$d" + "Tap to close folder" + "Tap to save rename" + "Folder closed" + "Folder renamed to %1$s" + "Folder: %1$s" + "Widgets" + "Wallpapers" + "Styles & wallpapers" + "Home settings" + "Disabled by your admin" + "Allow Home screen rotation" + "When phone is rotated" + "Notification dots" + "On" + "Off" + "Notification access needed" + "To show Notification Dots, turn on app notifications for %1$s" + "Change settings" + "Show notification dots" + "Add icon to Home screen" + "For new apps" + "Unknown" + "Remove" + "Search" + "This app is not installed" + "The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually." + "%1$s downloading, %2$s complete" + "%1$s waiting to install" + "%1$s widgets" + "Widgets list" + "Widgets list closed" + "Add to Home screen" + "Move item here" + "Item added to home screen" + "Item removed" + "Undo" + "Move item" + "Move to row %1$s column %2$s" + "Move to position %1$s" + "Move to favourites position %1$s" + "Item moved" + "Add to folder: %1$s" + "Add to folder with %1$s" + "Item added to folder" + "Create folder with: %1$s" + "Folder created" + "Move to Home screen" + "Re-size" + "Increase width" + "Increase height" + "Decrease width" + "Decrease height" + "Widget re-sized to width %1$s height %2$s" + "Short cuts" + "Shortcuts and notifications" + "Dismiss" + "Notification dismissed" + "Personal" + "Work" + "Work profile" + "Find work apps here" + "Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access." + "Managed by your organisation" + "Notifications and apps are off" + "Close" + "Closed" + "Failed: %1$s" + diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml new file mode 100644 index 0000000000..c741482983 --- /dev/null +++ b/res/values-en-rXC/strings.xml @@ -0,0 +1,142 @@ + + + + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎Launcher3‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎Work‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‏‎‎App isn\'t installed.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎App isn\'t available‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎Downloaded app disabled in Safe mode‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎Widgets disabled in Safe mode‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎Shortcut isn\'t available‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎Custom actions‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎Touch & hold to pick up a widget.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‎Double-tap & hold to pick up a widget or use custom actions.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎%1$d × %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎%1$d wide by %2$d high‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎Touch & hold to place manually‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎Add automatically‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎Search apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎Loading apps…‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎No apps found matching \"‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎\"‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎Search for more apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎App‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎Notifications‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎Touch & hold to pick up a shortcut.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎Double-tap & hold to pick up a shortcut or use custom actions.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎No more room on this Home screen.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎No more room in the Favorites tray‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎Apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‏‎‎‎Personal apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎Work apps list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎Home‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎Remove‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎Uninstall‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎App info‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎Install‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎install shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎Allows an app to add shortcuts without user intervention.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎read Home settings and shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‏‏‎‎‏‏‎Allows the app to read the settings and shortcuts in Home.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‎write Home settings and shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‎‎‏‎Allows the app to change the settings and shortcuts in Home.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ is not allowed to make phone calls‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎Problem loading widget‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎Setup‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‎‎This is a system app and can\'t be uninstalled.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‎‎Unnamed Folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎Disabled ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, has ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎ notifications‎‏‎‎‏‎ + ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎, has ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎ notification‎‏‎‎‏‎ + + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‎Page %1$d of %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎Home screen %1$d of %2$d‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎New home screen page‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‎Folder opened, ‎‏‎‎‏‏‎%1$d‎‏‎‎‏‏‏‎ by ‎‏‎‎‏‏‎%2$d‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎Tap to close folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎Tap to save rename‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎Folder closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎Folder renamed to ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎Folder: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎Widgets‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎Wallpapers‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎Styles & wallpapers‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎Home settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎Disabled by your admin‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎Allow Home screen rotation‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎When phone is rotated‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎Notification dots‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎On‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎Off‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎Notification access needed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎To show Notification Dots, turn on app notifications for ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎Change settings‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎Show notification dots‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‏‎Add icon to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎For new apps‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‎‎Unknown‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎Remove‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎Search‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎This app is not installed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ downloading, ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ complete‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ waiting to install‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ widgets‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎Widgets list‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎Widgets list closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎Add to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎Move item here‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎Item added to home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‏‎Item removed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎Undo‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎Move item‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎Move to row ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ column ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎Move to position ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎Move to favorites position ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‏‏‎Item moved‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎Add to folder: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎Add to folder with ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎Item added to folder‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎Create folder with: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎Folder created‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎Move to Home screen‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎Resize‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎Increase width‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‎Increase height‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎Decrease width‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎Decrease height‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎Widget resized to width ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ height ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎Shortcuts‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎Shortcuts and notifications‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎Dismiss‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎Notification dismissed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎Personal‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎Work‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎Work profile‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎Find work apps here‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎Each work app has a badge and is kept secure by your organization. Move apps to your Home screen for easier access.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎Managed by your organization‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎Notifications and apps are off‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎Close‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‎Closed‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎Failed: ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‎" + diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml index 3228dea004..da9da38e69 100644 --- a/res/values-gu/strings.xml +++ b/res/values-gu/strings.xml @@ -80,7 +80,7 @@ "વિજેટ્સ" "વૉલપેપર્સ" "શૈલીઓ અને વૉલપેપર" - "હોમ સેટિંગ્સ" + "હોમ સેટિંગ" "તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ" "હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો" "જ્યારે ફોન ફેરવવામાં આવે ત્યારે" diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml index ab14e8900b..458fb73817 100644 --- a/res/values-mk/strings.xml +++ b/res/values-mk/strings.xml @@ -80,9 +80,9 @@ "Виџети" "Тапети" "Стилови и тапети" - "Поставки за Home" + "Поставки за почетен екран" "Оневозможено од администраторот" - "Дозволете ротација на Почетниот екран" + "Дозволете ротација на почетниот екран" "Кога телефонот се ротира" "Точки за известување" "Вклучено" diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml index cc8d6641cc..37bd2d5f8b 100644 --- a/res/values-or/strings.xml +++ b/res/values-or/strings.xml @@ -84,7 +84,7 @@ "ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି" "ହୋମ୍‌ ସ୍କ୍ରୀନ୍ ବୁଲାଇବା ଅନୁମତି ଦିଅନ୍ତୁ" "ଯେତେବେଳେ ଫୋନକୁ ବୁଲାଯାଇଥାଏ" - "ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁଗୁଡ଼ିକ" + "ବିଜ୍ଞପ୍ତି ଡଟ୍ସ" "ଚାଲୁ କରନ୍ତୁ" "ବନ୍ଦ କରନ୍ତୁ" "ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ୍‌ ଆବଶ୍ୟକ ଅଟେ" diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 6e933a12e3..799b6b8f67 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -36,7 +36,7 @@ "தானாகவே சேர்" "பயன்பாடுகளில் தேடுக" "ஆப்ஸை ஏற்றுகிறது…" - "\"%1$s\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை" + "\"%1$s\" உடன் பொருந்தும் ஆப்ஸ் இல்லை" "கூடுதல் பயன்பாடுகளைத் தேடு" "ஆப்ஸ்" "அறிவிப்புகள்" From 1dd2e4819012b33588518ef434f996ac0b3ebbae Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 11 Oct 2019 10:58:24 -0700 Subject: [PATCH 102/109] Wait until listeners/end runnable is created before checking icon result. This prevents the case where original icon is in hidden state, then the view gets recycled and since there is no listener/end runnable the original icon is left in the hidden state. Bug: 142120338 Change-Id: I5f5bfa2a7c70d10869f51edf5c40bbaab1ef93bc --- .../android/launcher3/views/FloatingIconView.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 3912b44684..45c0d90971 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -767,11 +767,6 @@ public class FloatingIconView extends View implements // Match the position of the original view. view.matchPositionOf(launcher, originalView, isOpening, positionOut); - // Must be called after matchPositionOf so that we know what size to load. - if (shouldLoadIcon) { - view.checkIconResult(originalView, isOpening); - } - // We need to add it to the overlay, but keep it invisible until animation starts.. view.setVisibility(INVISIBLE); parent.addView(view); @@ -798,6 +793,14 @@ public class FloatingIconView extends View implements view.finish(dragLayer); } }; + + // Must be called after matchPositionOf so that we know what size to load. + // Must be called after the fastFinish listener and end runnable is created so that + // the icon is not left in a hidden state. + if (shouldLoadIcon) { + view.checkIconResult(originalView, isOpening); + } + return view; } From 59b148a440e144adb056fcd8d31628a73f676fe9 Mon Sep 17 00:00:00 2001 From: Sreyas Date: Fri, 27 Sep 2019 17:12:07 -0700 Subject: [PATCH 103/109] Create hooks for Recents Card plugin. This adds another card in the Recents Overview space which can show various items. Change-Id: Ifc36639ece8aa6b554bdbd3256f4195b1b220d68 --- .../quickstep/views/LauncherRecentsView.java | 85 +++++++++++++++++++ .../views/RecentsExtraViewContainer.java | 54 ++++++++++++ .../android/quickstep/views/RecentsView.java | 29 ++++++- .../systemui/plugins/RecentsExtraCard.java | 42 +++++++++ 4 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java create mode 100644 src_plugins/com/android/systemui/plugins/RecentsExtraCard.java diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index 764e0f314f..1545ec5110 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -35,6 +35,7 @@ import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; +import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Hotseat; @@ -46,11 +47,14 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; import com.android.launcher3.uioverrides.DejankBinderTracker; +import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.views.ScrimView; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.LayoutUtils; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.RecentsExtraCard; /** * {@link RecentsView} used in Launcher activity @@ -62,6 +66,25 @@ public class LauncherRecentsView extends RecentsView implements StateL private final TransformParams mTransformParams = new TransformParams(); + private RecentsExtraCard mRecentsExtraCardPlugin; + private RecentsExtraViewContainer mRecentsExtraViewContainer; + private PluginListener mRecentsExtraCardPluginListener = + new PluginListener() { + @Override + public void onPluginConnected(RecentsExtraCard recentsExtraCard, Context context) { + createRecentsExtraCard(); + mRecentsExtraCardPlugin = recentsExtraCard; + mRecentsExtraCardPlugin.setupView(context, mRecentsExtraViewContainer, mActivity); + } + + @Override + public void onPluginDisconnected(RecentsExtraCard plugin) { + removeView(mRecentsExtraViewContainer); + mRecentsExtraCardPlugin = null; + mRecentsExtraViewContainer = null; + } + }; + public LauncherRecentsView(Context context) { this(context, null); } @@ -298,4 +321,66 @@ public class LauncherRecentsView extends RecentsView implements StateL } return super.shouldStealTouchFromSiblingsBelow(ev); } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()) + .addPluginListener(mRecentsExtraCardPluginListener, RecentsExtraCard.class); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener( + mRecentsExtraCardPluginListener); + } + + @Override + protected int computeMinScrollX() { + if (canComputeScrollX() && !mIsRtl) { + return computeScrollX(); + } + return super.computeMinScrollX(); + } + + @Override + protected int computeMaxScrollX() { + if (canComputeScrollX() && mIsRtl) { + return computeScrollX(); + } + return super.computeMaxScrollX(); + } + + private boolean canComputeScrollX() { + return mRecentsExtraCardPlugin != null && getTaskViewCount() > 0 + && !mDisallowScrollToClearAll; + } + + private int computeScrollX() { + int scrollIndex = getTaskViewStartIndex() - 1; + while (scrollIndex >= 0 && getChildAt(scrollIndex) instanceof RecentsExtraViewContainer + && ((RecentsExtraViewContainer) getChildAt(scrollIndex)).isScrollable()) { + scrollIndex--; + } + return getScrollForPage(scrollIndex + 1); + } + + private void createRecentsExtraCard() { + mRecentsExtraViewContainer = new RecentsExtraViewContainer(getContext()); + FrameLayout.LayoutParams helpCardParams = + new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT); + mRecentsExtraViewContainer.setLayoutParams(helpCardParams); + mRecentsExtraViewContainer.setScrollable(true); + addView(mRecentsExtraViewContainer, 0); + } + + @Override + public void resetTaskVisuals() { + super.resetTaskVisuals(); + if (mRecentsExtraViewContainer != null) { + mRecentsExtraViewContainer.setAlpha(mContentAlpha); + } + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java new file mode 100644 index 0000000000..1ea6d4a245 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java @@ -0,0 +1,54 @@ +/* + * 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.quickstep.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +/** + * Empty view to house recents overview extra card + */ +public class RecentsExtraViewContainer extends FrameLayout implements RecentsView.PageCallbacks { + + private boolean mScrollable = false; + + public RecentsExtraViewContainer(Context context) { + super(context); + } + + public RecentsExtraViewContainer(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public RecentsExtraViewContainer(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + /** + * Determine whether the view should be scrolled to in the recents overview, similar to the + * taskviews. + * @return true if viewed should be scrolled to, false if not + */ + public boolean isScrollable() { + return mScrollable; + } + + public void setScrollable(boolean scrollable) { + this.mScrollable = scrollable; + } +} 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 ea0699159b..6120b9e9f9 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 @@ -17,6 +17,7 @@ package com.android.quickstep.views; import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_PIXELS; + import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; @@ -102,13 +103,13 @@ import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.Themes; import com.android.launcher3.util.ViewPool; import com.android.quickstep.RecentsAnimationController; +import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.RecentsModel; import com.android.quickstep.RecentsModel.TaskThumbnailChangeListener; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; import com.android.quickstep.ViewUtils; import com.android.quickstep.util.AppWindowAnimationHelper; -import com.android.quickstep.RecentsAnimationTargets; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -189,7 +190,7 @@ public abstract class RecentsView extends PagedView impl private final ViewPool mTaskViewPool; private boolean mDwbToastShown; - private boolean mDisallowScrollToClearAll; + protected boolean mDisallowScrollToClearAll; private boolean mOverlayEnabled; private boolean mFreezeViewVisibility; @@ -291,7 +292,7 @@ public abstract class RecentsView extends PagedView impl private LayoutTransition mLayoutTransition; @ViewDebug.ExportedProperty(category = "launcher") - private float mContentAlpha = 1; + protected float mContentAlpha = 1; @ViewDebug.ExportedProperty(category = "launcher") protected float mFullscreenProgress = 0; @@ -1850,6 +1851,7 @@ public abstract class RecentsView extends PagedView impl return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight()); } + /** If it's in the live tile mode, switch the running task into screenshot mode. */ public void switchToScreenshot(Runnable onFinishRunnable) { TaskView taskView = getRunningTaskView(); @@ -1864,4 +1866,25 @@ public abstract class RecentsView extends PagedView impl taskView.getThumbnail().refresh(); ViewUtils.postDraw(taskView, onFinishRunnable); } + + @Override + public void addView(View child, int index) { + super.addView(child, index); + if (isExtraCardView(child, index)) { + mTaskViewStartIndex++; + } + } + + @Override + public void removeView(View view) { + if (isExtraCardView(view, indexOfChild(view))) { + mTaskViewStartIndex--; + } + super.removeView(view); + } + + private boolean isExtraCardView(View view, int index) { + return !(view instanceof TaskView) && !(view instanceof ClearAllButton) + && index <= mTaskViewStartIndex; + } } diff --git a/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java new file mode 100644 index 0000000000..0ebea3d470 --- /dev/null +++ b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java @@ -0,0 +1,42 @@ +/* + * 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.systemui.plugins; + +import android.app.Activity; +import android.content.Context; +import android.widget.FrameLayout; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +/** + * Implement this interface to allow extra card on recents overview. + */ +@ProvidesInterface(action = RecentsExtraCard.ACTION, version = RecentsExtraCard.VERSION) +public interface RecentsExtraCard extends Plugin { + + String ACTION = "com.android.systemui.action.PLUGIN_RECENTS_EXTRA_CARD"; + int VERSION = 1; + + /** + * Sets up the recents overview extra card and fills in data. + * + * @param context Plugin context + * @param frameLayout PlaceholderView + * @param activity Recents activity to hold extra view + */ + void setupView(Context context, FrameLayout frameLayout, Activity activity); +} From 8e02d17fa2ef0708cae4daa0f6c5124fa06a719f Mon Sep 17 00:00:00 2001 From: Sreyas Date: Fri, 27 Sep 2019 17:12:07 -0700 Subject: [PATCH 104/109] Create hooks for Recents Card plugin. This adds another card in the Recents Overview space which can show various items. Change-Id: Ifc36639ece8aa6b554bdbd3256f4195b1b220d68 Merged-In: Ifc36639ece8aa6b554bdbd3256f4195b1b220d68 --- .../quickstep/views/LauncherRecentsView.java | 85 +++++++++++++++++++ .../views/RecentsExtraViewContainer.java | 54 ++++++++++++ .../android/quickstep/views/RecentsView.java | 26 +++++- .../systemui/plugins/RecentsExtraCard.java | 42 +++++++++ 4 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java create mode 100644 src_plugins/com/android/systemui/plugins/RecentsExtraCard.java diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index b601834f3b..c2cb720ae9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -35,6 +35,7 @@ import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; +import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Hotseat; @@ -45,11 +46,14 @@ import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; +import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.views.ScrimView; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.util.ClipAnimationHelper; import com.android.quickstep.util.ClipAnimationHelper.TransformParams; import com.android.quickstep.util.LayoutUtils; +import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.RecentsExtraCard; /** * {@link RecentsView} used in Launcher activity @@ -61,6 +65,25 @@ public class LauncherRecentsView extends RecentsView implements StateL private final TransformParams mTransformParams = new TransformParams(); + private RecentsExtraCard mRecentsExtraCardPlugin; + private RecentsExtraViewContainer mRecentsExtraViewContainer; + private PluginListener mRecentsExtraCardPluginListener = + new PluginListener() { + @Override + public void onPluginConnected(RecentsExtraCard recentsExtraCard, Context context) { + createRecentsExtraCard(); + mRecentsExtraCardPlugin = recentsExtraCard; + mRecentsExtraCardPlugin.setupView(context, mRecentsExtraViewContainer, mActivity); + } + + @Override + public void onPluginDisconnected(RecentsExtraCard plugin) { + removeView(mRecentsExtraViewContainer); + mRecentsExtraCardPlugin = null; + mRecentsExtraViewContainer = null; + } + }; + public LauncherRecentsView(Context context) { this(context, null); } @@ -285,4 +308,66 @@ public class LauncherRecentsView extends RecentsView implements StateL } return super.shouldStealTouchFromSiblingsBelow(ev); } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()) + .addPluginListener(mRecentsExtraCardPluginListener, RecentsExtraCard.class); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + PluginManagerWrapper.INSTANCE.get(getContext()).removePluginListener( + mRecentsExtraCardPluginListener); + } + + @Override + protected int computeMinScrollX() { + if (canComputeScrollX() && !mIsRtl) { + return computeScrollX(); + } + return super.computeMinScrollX(); + } + + @Override + protected int computeMaxScrollX() { + if (canComputeScrollX() && mIsRtl) { + return computeScrollX(); + } + return super.computeMaxScrollX(); + } + + private boolean canComputeScrollX() { + return mRecentsExtraCardPlugin != null && getTaskViewCount() > 0 + && !mDisallowScrollToClearAll; + } + + private int computeScrollX() { + int scrollIndex = getTaskViewStartIndex() - 1; + while (scrollIndex >= 0 && getChildAt(scrollIndex) instanceof RecentsExtraViewContainer + && ((RecentsExtraViewContainer) getChildAt(scrollIndex)).isScrollable()) { + scrollIndex--; + } + return getScrollForPage(scrollIndex + 1); + } + + private void createRecentsExtraCard() { + mRecentsExtraViewContainer = new RecentsExtraViewContainer(getContext()); + FrameLayout.LayoutParams helpCardParams = + new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT); + mRecentsExtraViewContainer.setLayoutParams(helpCardParams); + mRecentsExtraViewContainer.setScrollable(true); + addView(mRecentsExtraViewContainer, 0); + } + + @Override + public void resetTaskVisuals() { + super.resetTaskVisuals(); + if (mRecentsExtraViewContainer != null) { + mRecentsExtraViewContainer.setAlpha(mContentAlpha); + } + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java new file mode 100644 index 0000000000..1ea6d4a245 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java @@ -0,0 +1,54 @@ +/* + * 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.quickstep.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +/** + * Empty view to house recents overview extra card + */ +public class RecentsExtraViewContainer extends FrameLayout implements RecentsView.PageCallbacks { + + private boolean mScrollable = false; + + public RecentsExtraViewContainer(Context context) { + super(context); + } + + public RecentsExtraViewContainer(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public RecentsExtraViewContainer(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + /** + * Determine whether the view should be scrolled to in the recents overview, similar to the + * taskviews. + * @return true if viewed should be scrolled to, false if not + */ + public boolean isScrollable() { + return mScrollable; + } + + public void setScrollable(boolean scrollable) { + this.mScrollable = scrollable; + } +} 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 02c43e4ad0..6ad3cc686a 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 @@ -17,6 +17,7 @@ package com.android.quickstep.views; import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_PIXELS; + import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; @@ -186,7 +187,7 @@ public abstract class RecentsView extends PagedView impl private final ViewPool mTaskViewPool; private boolean mDwbToastShown; - private boolean mDisallowScrollToClearAll; + protected boolean mDisallowScrollToClearAll; private boolean mOverlayEnabled; private boolean mFreezeViewVisibility; @@ -288,7 +289,7 @@ public abstract class RecentsView extends PagedView impl private LayoutTransition mLayoutTransition; @ViewDebug.ExportedProperty(category = "launcher") - private float mContentAlpha = 1; + protected float mContentAlpha = 1; @ViewDebug.ExportedProperty(category = "launcher") protected float mFullscreenProgress = 0; @@ -1821,4 +1822,25 @@ public abstract class RecentsView extends PagedView impl final WindowInsets insets = getRootWindowInsets(); return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight()); } + + @Override + public void addView(View child, int index) { + super.addView(child, index); + if (isExtraCardView(child, index)) { + mTaskViewStartIndex++; + } + } + + @Override + public void removeView(View view) { + if (isExtraCardView(view, indexOfChild(view))) { + mTaskViewStartIndex--; + } + super.removeView(view); + } + + private boolean isExtraCardView(View view, int index) { + return !(view instanceof TaskView) && !(view instanceof ClearAllButton) + && index <= mTaskViewStartIndex; + } } diff --git a/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java new file mode 100644 index 0000000000..0ebea3d470 --- /dev/null +++ b/src_plugins/com/android/systemui/plugins/RecentsExtraCard.java @@ -0,0 +1,42 @@ +/* + * 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.systemui.plugins; + +import android.app.Activity; +import android.content.Context; +import android.widget.FrameLayout; + +import com.android.systemui.plugins.annotations.ProvidesInterface; + +/** + * Implement this interface to allow extra card on recents overview. + */ +@ProvidesInterface(action = RecentsExtraCard.ACTION, version = RecentsExtraCard.VERSION) +public interface RecentsExtraCard extends Plugin { + + String ACTION = "com.android.systemui.action.PLUGIN_RECENTS_EXTRA_CARD"; + int VERSION = 1; + + /** + * Sets up the recents overview extra card and fills in data. + * + * @param context Plugin context + * @param frameLayout PlaceholderView + * @param activity Recents activity to hold extra view + */ + void setupView(Context context, FrameLayout frameLayout, Activity activity); +} From c062580b5a7fcc049266afdf73d5b038713f036e Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 11 Oct 2019 12:58:18 -0700 Subject: [PATCH 105/109] Wait for the task to be in recents before validation - There are two issues: 1) Currently the system does not add the task to the task list until the activity starting the task has been resumed (to be fixed in a follow up platform CL). When the three activities are started in sequence, it's possible for one of the activities to not reach the resumed state leading to an unexpected number of recent tasks the next time it's fetched. 2) When swiping up, it may take time for getTasks to return and call applyLoadPlan, so try and wait until the task views have had a chance to be applied before continuing. 3) Use the launcher activity tracker instead of activity rule since it will return the same activity even after the activity is destroyed - Move the margin handling to the caller instead of the scroll method Bug: 141580748 Change-Id: I2b7634f5ac6869ba4b369b3bd60e0f63747c0f0b --- .../QuickstepTestInformationHandler.java | 38 ++++++++++++----- .../quickstep/FallbackRecentsTest.java | 41 ++++++++++++++----- .../testing/TestInformationHandler.java | 8 +--- .../launcher3/testing/TestProtocol.java | 1 + .../android/launcher3/tapl/BaseOverview.java | 4 +- .../tapl/LauncherInstrumentation.java | 23 ++++++++--- .../com/android/launcher3/tapl/Widgets.java | 2 +- .../com/android/launcher3/tapl/Workspace.java | 4 +- 8 files changed, 83 insertions(+), 38 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index 1bbeca47f1..daaa95b01b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -5,16 +5,18 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.content.Context; import android.os.Bundle; -import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.testing.TestInformationHandler; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController; -import com.android.launcher3.util.DefaultDisplay; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.recents.model.Task; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; public class QuickstepTestInformationHandler extends TestInformationHandler { @@ -54,10 +56,8 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { final int leftMargin = MAIN_EXECUTOR.submit(() -> getRecentsView().getLeftGestureMargin()).get(); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, leftMargin); - } catch (ExecutionException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); } return response; } @@ -67,13 +67,31 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { final int rightMargin = MAIN_EXECUTOR.submit(() -> getRecentsView().getRightGestureMargin()).get(); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, rightMargin); - } catch (ExecutionException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); } return response; } + + case TestProtocol.REQUEST_RECENT_TASKS_LIST: { + ArrayList taskBaseIntentComponents = new ArrayList<>(); + CountDownLatch latch = new CountDownLatch(1); + RecentsModel.INSTANCE.get(mContext).getTasks((tasks) -> { + for (Task t : tasks) { + taskBaseIntentComponents.add( + t.key.baseIntent.getComponent().flattenToString()); + } + latch.countDown(); + }); + try { + latch.await(2, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + response.putStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD, + taskBaseIntentComponents); + return response; + } } return super.call(method); diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index fcbc314e2f..aa5fce19d9 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -22,6 +22,7 @@ import static androidx.test.InstrumentationRegistry.getInstrumentation; import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS; import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage; import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess; +import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_ACTIVITY_TIMEOUT; import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT; import static com.android.launcher3.ui.AbstractLauncherUiTest.resolveSystemApp; import static com.android.launcher3.ui.AbstractLauncherUiTest.startAppFast; @@ -36,6 +37,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.app.Instrumentation; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -55,7 +57,6 @@ import com.android.launcher3.tapl.TestHelpers; import com.android.launcher3.testcomponent.TestCommandReceiver; import com.android.launcher3.util.Wait; import com.android.launcher3.util.rule.FailureWatcher; -import com.android.launcher3.util.rule.SimpleActivityRule; import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; import com.android.quickstep.views.RecentsView; @@ -86,10 +87,6 @@ public class FallbackRecentsTest { @Rule public final TestRule mOrderSensitiveRules; - @Rule - public final SimpleActivityRule mActivityMonitor = - new SimpleActivityRule(RecentsActivity.class); - public FallbackRecentsTest() throws RemoteException { Instrumentation instrumentation = getInstrumentation(); Context context = instrumentation.getContext(); @@ -143,7 +140,7 @@ public class FallbackRecentsTest { @NavigationModeSwitch @Test public void goToOverviewFromApp() { - startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); + startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); mLauncher.getBackground().switchToOverview(); } @@ -159,7 +156,7 @@ public class FallbackRecentsTest { if (!TestHelpers.isInLauncherProcess()) return null; Object[] result = new Object[1]; Wait.atMost("Failed to get from recents", () -> MAIN_EXECUTOR.submit(() -> { - RecentsActivity activity = mActivityMonitor.getActivity(); + RecentsActivity activity = RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); if (activity == null) { return false; } @@ -177,13 +174,15 @@ public class FallbackRecentsTest { @NavigationModeSwitch @Test public void testOverview() { - startAppFast(getAppPackageName()); - startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); + startAppFastAndWaitForRecentTask(getAppPackageName()); + startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); startTestActivity(2); + Wait.atMost("Expected three apps in the task list", + () -> mLauncher.getRecentTasks().size() >= 3, DEFAULT_ACTIVITY_TIMEOUT); BaseOverview overview = mLauncher.getBackground().switchToOverview(); - executeOnRecents( - recents -> assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3)); + executeOnRecents(recents -> + assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3)); // Test flinging forward and backward. overview.flingForward(); @@ -229,4 +228,24 @@ public class FallbackRecentsTest { private int getTaskCount(RecentsActivity recents) { return recents.getOverviewPanel().getTaskViewCount(); } + + /** + * Workaround for b/141580748, there was an issue where the recent task is only updated when the + * activity starting the task is resumed. In this case, we should wait until the task is in + * the recents task list before continuing. + */ + private void startAppFastAndWaitForRecentTask(String packageName) { + startAppFast(packageName); + Wait.atMost("Expected app in task list", + () -> containsRecentTaskWithPackage(packageName), DEFAULT_ACTIVITY_TIMEOUT); + } + + private boolean containsRecentTaskWithPackage(String packageName) { + for (ComponentName cn : mLauncher.getRecentTasks()) { + if (cn.getPackageName().equals(packageName)) { + return true; + } + } + return false; + } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index fa9cc3ad61..8296cf962b 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -115,9 +115,7 @@ public class TestInformationHandler implements ResourceBasedOverride { mLauncher.getAppsView().getAppsStore().getDeferUpdatesFlags()).get(); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, deferUpdatesFlags); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } catch (InterruptedException e) { + } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } break; @@ -130,9 +128,7 @@ public class TestInformationHandler implements ResourceBasedOverride { .get(); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, deferUpdatesFlags); - } catch (ExecutionException e) { - throw new RuntimeException(e); - } catch (InterruptedException e) { + } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } break; diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index add45650c1..5110977ae4 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -75,6 +75,7 @@ public final class TestProtocol { public static final String REQUEST_JAVA_LEAK = "java-leak"; public static final String REQUEST_NATIVE_LEAK = "native-leak"; public static final String REQUEST_VIEW_LEAK = "view-leak"; + public static final String REQUEST_RECENT_TASKS_LIST = "recent-tasks-list"; 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/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index 338f714215..8ccfc05bf7 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -55,7 +55,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { final int leftMargin = mLauncher.getTestInfo( TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN). getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); - mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin, 0, 0, 0), 20); + mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20); verifyActiveContainer(); } } @@ -89,7 +89,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { final int rightMargin = mLauncher.getTestInfo( TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN). getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); - mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin, 0), 20); + mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin + 1, 0), 20); verifyActiveContainer(); } } diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 3248d6ada0..484cbb61c3 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -64,8 +64,7 @@ import com.android.launcher3.ResourceUtils; import com.android.launcher3.testing.TestProtocol; import com.android.systemui.shared.system.QuickStepContract; -import org.junit.Assert; - +import java.util.ArrayList; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; @@ -78,6 +77,8 @@ import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import java.util.function.Function; +import org.junit.Assert; + /** * The main tapl object. The only object that can be explicitly constructed by the using code. It * produces all other objects. @@ -822,8 +823,8 @@ public final class LauncherInstrumentation { switch (direction) { case UP: { startX = endX = rect.centerX(); - startY = rect.top + 1; - endY = rect.bottom; + startY = rect.top; + endY = rect.bottom - 1; } break; case DOWN: { @@ -834,8 +835,8 @@ public final class LauncherInstrumentation { break; case LEFT: { startY = endY = rect.centerY(); - startX = rect.left + 1; - endX = rect.right; + startX = rect.left; + endX = rect.right - 1; } break; case RIGHT: { @@ -997,4 +998,14 @@ public final class LauncherInstrumentation { public void produceViewLeak() { getTestInfo(TestProtocol.REQUEST_VIEW_LEAK); } + + public ArrayList getRecentTasks() { + ArrayList tasks = new ArrayList<>(); + ArrayList components = getTestInfo(TestProtocol.REQUEST_RECENT_TASKS_LIST) + .getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD); + for (String s : components) { + tasks.add(ComponentName.unflattenFromString(s)); + } + return tasks; + } } \ No newline at end of file diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 01956930d5..5fcaa557df 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -48,7 +48,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { mLauncher.scroll( widgetsContainer, Direction.DOWN, - new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer)), + new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer) + 1), FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { verifyActiveContainer(); diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 0aa36ddbbe..d1261e07be 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -181,7 +181,7 @@ public final class Workspace extends Home { public void flingForward() { final UiObject2 workspace = verifyActiveContainer(); mLauncher.scroll(workspace, Direction.RIGHT, - new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0), + new Rect(0, 0, mLauncher.getEdgeSensitivityWidth() + 1, 0), FLING_STEPS); verifyActiveContainer(); } @@ -193,7 +193,7 @@ public final class Workspace extends Home { public void flingBackward() { final UiObject2 workspace = verifyActiveContainer(); mLauncher.scroll(workspace, Direction.LEFT, - new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0), + new Rect(mLauncher.getEdgeSensitivityWidth() + 1, 0, 0, 0), FLING_STEPS); verifyActiveContainer(); } From eb27edffc296687002ef9b8c3f93c859aa4b4d69 Mon Sep 17 00:00:00 2001 From: Zak Cohen Date: Mon, 14 Oct 2019 10:55:15 -0700 Subject: [PATCH 106/109] Suppress ViewInflationDuringSwipeUp test. Test is failing and blocking drop. Only failing on TH, passing locally. Tracked in b/141579810 Bug:141579810 Change-Id: Iadf8098cad22835b026984c0a9ea5122054b484b --- .../src/com/android/quickstep/ViewInflationDuringSwipeUp.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java index 8b7c7b793f..f8f22a1943 100644 --- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java +++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java @@ -42,6 +42,7 @@ import android.view.ViewConfiguration; import android.widget.RemoteViews; import androidx.test.filters.LargeTest; +import androidx.test.filters.Suppress; import androidx.test.runner.AndroidJUnit4; import androidx.test.uiautomator.By; import androidx.test.uiautomator.UiDevice; @@ -77,7 +78,10 @@ import java.util.function.IntConsumer; * directly (ex: new LinearLayout) * Using ExtendedMockito: Mocking static methods from platform classes (loaded in zygote) makes * the main thread extremely slow and untestable + * + * Suppressed until b/141579810 is resolved */ +@Suppress @LargeTest @RunWith(AndroidJUnit4.class) public class ViewInflationDuringSwipeUp extends AbstractQuickStepTest { From ce25a2bf68e13ea32ead7934d7c570a62e404fe2 Mon Sep 17 00:00:00 2001 From: vadimt Date: Fri, 11 Oct 2019 19:02:12 -0700 Subject: [PATCH 107/109] Adding tracing for a lab-only flake Bug: 142514365 Change-Id: I9c93ecabbcbad6d4683d595587831d8465e62ee8 --- .../quickstep/QuickstepTestInformationHandler.java | 8 ++++++++ .../android/quickstep/TouchInteractionService.java | 8 ++++++++ src/com/android/launcher3/LauncherModel.java | 5 +++++ .../launcher3/testing/TestInformationHandler.java | 6 ++++++ src/com/android/launcher3/testing/TestProtocol.java | 1 + src/com/android/launcher3/util/ActivityTracker.java | 12 ++++++++++++ 6 files changed, 40 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index daaa95b01b..ce533a699a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -4,7 +4,10 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.content.Context; import android.os.Bundle; +import android.util.Log; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.testing.TestInformationHandler; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.uioverrides.states.OverviewState; @@ -109,6 +112,11 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { @Override protected boolean isLauncherInitialized() { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, + "isLauncherInitialized.TouchInteractionService.isInitialized=" + + TouchInteractionService.isInitialized()); + } return super.isLauncherInitialized() && TouchInteractionService.isInitialized(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 4b7ae6f426..a34638dae4 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -53,6 +53,8 @@ import androidx.annotation.UiThread; import androidx.annotation.WorkerThread; import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.config.FeatureFlags; @@ -131,6 +133,9 @@ public class TouchInteractionService extends Service implements .setProxy(proxy)); MAIN_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor); MAIN_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */)); + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "TIS initialized"); + } sIsInitialized = true; } @@ -380,6 +385,9 @@ public class TouchInteractionService extends Service implements @Override public void onDestroy() { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "TIS destroyed"); + } sIsInitialized = false; if (mDeviceState.isUserUnlocked()) { mInputConsumer.unregisterInputConsumer(); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index bea25e07ee..b22d137b2f 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -53,6 +53,7 @@ import com.android.launcher3.model.UserLockStateChangedTask; import com.android.launcher3.pm.InstallSessionTracker; import com.android.launcher3.pm.PackageInstallInfo; import com.android.launcher3.shortcuts.DeepShortcutManager; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.PackageUserKey; @@ -92,6 +93,10 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi private boolean mModelLoaded; public boolean isModelLoaded() { synchronized (mLock) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, + "isModelLoaded: " + mModelLoaded + ", " + mLoaderTask); + } return mModelLoaded && mLoaderTask == null; } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 8296cf962b..d0e648ffc9 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -24,6 +24,7 @@ import android.graphics.Bitmap; import android.graphics.Color; import android.os.Bundle; import android.os.Debug; +import android.util.Log; import android.view.View; import com.android.launcher3.DeviceProfile; @@ -176,6 +177,11 @@ public class TestInformationHandler implements ResourceBasedOverride { } protected boolean isLauncherInitialized() { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, + "isLauncherInitialized " + Launcher.ACTIVITY_TRACKER.getCreatedActivity() + ", " + + LauncherAppState.getInstance(mContext).getModel().isModelLoaded()); + } return Launcher.ACTIVITY_TRACKER.getCreatedActivity() == null || LauncherAppState.getInstance(mContext).getModel().isModelLoaded(); } diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 5110977ae4..faf0ff6c45 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -85,4 +85,5 @@ public final class TestProtocol { public static final String NO_DRAG_TO_WORKSPACE = "b/138729456"; public static final String APP_NOT_DISABLED = "b/139891609"; public static final String NO_CONTEXT_MENU = "b/141770616"; + public static final String LAUNCHER_DIDNT_INITIALIZE = "b/142514365"; } diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java index e85a4e8058..b4f361f36c 100644 --- a/src/com/android/launcher3/util/ActivityTracker.java +++ b/src/com/android/launcher3/util/ActivityTracker.java @@ -20,10 +20,12 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.content.Intent; import android.os.Bundle; import android.os.IBinder; +import android.util.Log; import androidx.annotation.Nullable; import com.android.launcher3.BaseActivity; +import com.android.launcher3.testing.TestProtocol; import java.lang.ref.WeakReference; @@ -43,7 +45,13 @@ public final class ActivityTracker implements Runnable { } public void onActivityDestroyed(T activity) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "onActivityDestroyed"); + } if (mCurrentActivity.get() == activity) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "onActivityDestroyed: clear"); + } mCurrentActivity.clear(); } } @@ -89,6 +97,10 @@ public final class ActivityTracker implements Runnable { } public boolean handleCreate(T activity) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, + "ActivityTracker.handleCreate " + mCurrentActivity.get() + " => " + activity); + } mCurrentActivity = new WeakReference<>(activity); return handleIntent(activity, activity.getIntent(), false, false); } From 1e73e320b78adaac5dd74835ad6a51a3c5589fd3 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 7 Oct 2019 17:08:20 -0700 Subject: [PATCH 108/109] Add tests for quick switch from an app and home Bug: 140252765 Change-Id: I5621b614ae2d8cd3db03cae818cf8b8c1c6cb20f --- .../android/quickstep/TaplTestsQuickstep.java | 58 +++++++++++++++++-- .../android/launcher3/tapl/Background.java | 41 +++++++++++++ .../tapl/com/android/launcher3/tapl/Home.java | 6 ++ 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java index 885fdbf423..41f4a82175 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java @@ -17,6 +17,7 @@ package com.android.quickstep; import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -34,6 +35,7 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.tapl.AllApps; import com.android.launcher3.tapl.AllAppsFromOverview; import com.android.launcher3.tapl.Background; +import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel; import com.android.launcher3.tapl.Overview; import com.android.launcher3.tapl.OverviewTask; import com.android.launcher3.tapl.TestHelpers; @@ -210,16 +212,21 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { @PortraitLandscape public void testBackground() throws Exception { startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); + final Background background = getAndAssertBackground(); + + assertNotNull("Background.switchToOverview() returned null", background.switchToOverview()); + assertTrue("Launcher internal state didn't switch to Overview", + isInState(LauncherState.OVERVIEW)); + } + + private Background getAndAssertBackground() { final Background background = mLauncher.getBackground(); assertNotNull("Launcher.getBackground() returned null", background); executeOnLauncher(launcher -> assertTrue( "Launcher activity is the top activity; expecting another activity to be the top " + "one", isInBackground(launcher))); - - assertNotNull("Background.switchToOverview() returned null", background.switchToOverview()); - assertTrue("Launcher internal state didn't switch to Overview", - isInState(LauncherState.OVERVIEW)); + return background; } @Test @@ -237,4 +244,47 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL)); assertNotNull("getHome returned null", mLauncher.getWorkspace()); } + + @Test + @NavigationModeSwitch + @PortraitLandscape + public void testQuickSwitchFromApp() throws Exception { + startAppFast(getAppPackageName()); + startTestActivity(2); + String calculatorPackage = resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR); + startAppFast(calculatorPackage); + + Background background = getAndAssertBackground(); + background.quickSwitchToPreviousApp(); + assertTrue("The first app we should have quick switched to is not running", + isTestActivityRunning("TestActivity2")); + + background = getAndAssertBackground(); + background.quickSwitchToPreviousApp(); + if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) { + // 3-button mode toggles between 2 apps, rather than going back further. + assertTrue("Second quick switch should have returned to the first app.", + mDevice.wait(Until.hasObject(By.pkg(calculatorPackage)), DEFAULT_UI_TIMEOUT)); + } else { + assertTrue("The second app we should have quick switched to is not running", + isTestActivityRunning("Test Pin Item")); + } + getAndAssertBackground(); + } + + private boolean isTestActivityRunning(String activityLabel) { + return mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()).text(activityLabel)), + DEFAULT_UI_TIMEOUT); + } + + @Test + @NavigationModeSwitch + @PortraitLandscape + public void testQuickSwitchFromHome() throws Exception { + startTestActivity(2); + mLauncher.pressHome().quickSwitchToPreviousApp(); + assertTrue("The most recent task is not running after quick switching from home", + isTestActivityRunning("TestActivity2")); + getAndAssertBackground(); + } } diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java index bcce8ef579..0dd3e775c5 100644 --- a/tests/tapl/com/android/launcher3/tapl/Background.java +++ b/tests/tapl/com/android/launcher3/tapl/Background.java @@ -23,6 +23,7 @@ import android.os.SystemClock; import android.view.MotionEvent; import androidx.annotation.NonNull; +import androidx.test.uiautomator.UiObject2; import com.android.launcher3.testing.TestProtocol; @@ -114,6 +115,46 @@ public class Background extends LauncherInstrumentation.VisibleContainer { } } + /** + * Swipes right or double presses the square button to switch to the previous app. + */ + public Background quickSwitchToPreviousApp() { + try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( + "want to quick switch to the previous app")) { + verifyActiveContainer(); + quickSwitchToPreviousApp(getExpectedStateForQuickSwitch()); + return new Background(mLauncher); + } + } + + protected int getExpectedStateForQuickSwitch() { + return BACKGROUND_APP_STATE_ORDINAL; + } + + protected void quickSwitchToPreviousApp(int expectedState) { + switch (mLauncher.getNavigationModel()) { + case ZERO_BUTTON: + // Fall through, zero button and two button modes behave the same. + case TWO_BUTTON: { + // Swipe from the bottom left to the bottom right of the screen. + final int startX = 0; + final int startY = getSwipeStartY(); + final int endX = mLauncher.getDevice().getDisplayWidth(); + final int endY = startY; + mLauncher.swipeToState(startX, startY, endX, endY, 20, expectedState); + break; + } + + case THREE_BUTTON: + // Double press the recents button. + UiObject2 recentsButton = mLauncher.waitForSystemUiObject("recent_apps"); + recentsButton.click(); + mLauncher.getOverview(); + recentsButton.click(); + break; + } + } + protected String getSwipeHeightRequestName() { return TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT; } diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java index cfc43749d1..e0fe933ee9 100644 --- a/tests/tapl/com/android/launcher3/tapl/Home.java +++ b/tests/tapl/com/android/launcher3/tapl/Home.java @@ -17,6 +17,7 @@ package com.android.launcher3.tapl; import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL; +import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL; import androidx.annotation.NonNull; @@ -58,4 +59,9 @@ public abstract class Home extends Background { } } } + + @Override + protected int getExpectedStateForQuickSwitch() { + return QUICK_SWITCH_STATE_ORDINAL; + } } \ No newline at end of file From b67a15ddd9de4c49432dc4a4ba086e5bb1ef7323 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Tue, 15 Oct 2019 20:51:51 +0000 Subject: [PATCH 109/109] Revert "Merging ub-launcher3-master, build 5938524" This reverts commit 7cb721fa819992391045e70e5c109d8d43099a78. Reason for revert: Change-Id: I10ebd177cc98be896282147df481b05f28241758 --- Android.mk | 6 +- .../GoLauncherAppTransitionManagerImpl.java | 14 +- .../uioverrides/RecentsUiFactory.java | 2 +- .../AppToOverviewAnimationProvider.java | 29 +- ... => FallbackActivityControllerHelper.java} | 20 +- ...face.java => GoActivityControlHelper.java} | 4 +- ... => LauncherActivityControllerHelper.java} | 9 +- .../quickstep/OverviewCommandHelper.java | 20 +- .../quickstep/TouchInteractionService.java | 45 +- .../launcher3/icons/BaseIconFactory.java | 12 +- .../launcher3/icons/cache/BaseIconCache.java | 14 +- .../launcher3/icons/cache/CachingLogic.java | 7 +- .../icons/cache/IconCacheUpdateHandler.java | 4 +- .../LauncherAppTransitionManagerImpl.java | 19 +- .../launcher3/LauncherInitListenerEx.java | 2 +- .../uioverrides/RecentsUiFactory.java | 43 +- .../states/BackgroundAppState.java | 2 +- .../FlingAndHoldTouchController.java | 32 +- .../QuickSwitchTouchController.java | 4 +- .../AppToOverviewAnimationProvider.java | 38 +- .../android/quickstep/BaseSwipeUpHandler.java | 152 ++--- ... => FallbackActivityControllerHelper.java} | 20 +- ... => LauncherActivityControllerHelper.java} | 66 +-- .../quickstep/OverviewCommandHelper.java | 52 +- .../QuickstepTestInformationHandler.java | 58 +- .../android/quickstep/RecentsActivity.java | 30 +- .../quickstep/RecentsAnimationWrapper.java} | 164 +++--- .../android/quickstep/SwipeSharedState.java | 75 +-- .../android/quickstep/TaskSystemShortcut.java | 21 +- .../com/android/quickstep/TaskViewUtils.java | 58 +- .../quickstep/TouchInteractionService.java | 523 +++++++++++------- .../src/com/android/quickstep/ViewUtils.java | 74 --- .../WindowTransformSwipeHandler.java | 183 +++--- .../fallback/FallbackRecentsView.java | 2 +- .../AccessibilityInputConsumer.java | 51 +- ...sumer.java => AssistantTouchConsumer.java} | 87 +-- .../inputconsumers/DelegateInputConsumer.java | 1 - .../DeviceLockedInputConsumer.java | 77 ++- .../FallbackNoButtonInputConsumer.java | 58 +- .../inputconsumers}/InputConsumer.java | 4 +- .../OtherActivityInputConsumer.java | 53 +- .../inputconsumers/OverviewInputConsumer.java | 19 +- .../OverviewWithoutFocusInputConsumer.java | 18 +- .../QuickCaptureInputConsumer.java | 221 -------- .../ResetGestureInputConsumer.java | 1 - .../ScreenPinnedInputConsumer.java | 29 +- ...onHelper.java => ClipAnimationHelper.java} | 164 +++--- .../quickstep}/util/ObjectWrapper.java | 2 +- .../util/RecentsAnimationListenerSet.java} | 117 ++-- .../util/StaggeredWorkspaceAnim.java | 52 +- .../util/SwipeAnimationTargetSet.java | 119 ++++ .../quickstep/views/LauncherRecentsView.java | 148 +---- .../views/RecentsExtraViewContainer.java | 54 -- .../android/quickstep/views/RecentsView.java | 121 +--- .../android/quickstep/views/TaskMenuView.java | 2 - .../quickstep/views/TaskThumbnailView.java | 67 +-- .../launcher3/LauncherAnimationRunner.java | 10 +- .../launcher3/LauncherInitListener.java | 31 +- .../QuickstepAppTransitionManagerImpl.java | 97 ++-- .../uioverrides/BackButtonAlphaHandler.java | 19 +- .../uioverrides/DejankBinderTracker.java | 4 +- .../launcher3/uioverrides/UiFactory.java | 25 +- .../PortraitStatesTouchController.java | 23 +- .../StatusBarTouchController.java | 26 +- ...erface.java => ActivityControlHelper.java} | 25 +- .../quickstep/BaseRecentsActivity.java | 8 +- .../com/android/quickstep/GestureState.java | 36 -- .../quickstep/OverviewComponentObserver.java | 34 +- .../quickstep/OverviewInteractionState.java | 146 +++++ .../quickstep/RecentsActivityTracker.java | 130 +++++ .../RecentsAnimationDeviceState.java | 426 -------------- .../quickstep/RecentsAnimationTargets.java | 53 -- .../com/android/quickstep/RecentsModel.java | 59 +- .../quickstep/SysUINavigationMode.java | 2 +- .../com/android/quickstep/SystemUiProxy.java | 285 ---------- .../src/com/android/quickstep/TaskUtils.java | 9 +- .../logging/StatsLogCompatManager.java | 115 +--- .../quickstep/util/ActivityInitListener.java | 60 -- .../util/RemoteAnimationProvider.java | 9 +- .../RemoteAnimationTargetSet.java} | 12 +- .../util/RemoteFadeOutAnimationListener.java | 8 +- .../quickstep/views/ShelfScrimView.java | 2 +- .../quickstep/AppPredictionsUITests.java | 4 +- .../quickstep/FallbackRecentsTest.java | 71 +-- .../quickstep/NavigationModeSwitchRule.java | 2 +- .../StartLauncherViaGestureTests.java | 5 + .../android/quickstep/TaplTestsQuickstep.java | 58 +- .../quickstep/ViewInflationDuringSwipeUp.java | 280 ---------- res/anim/slide_in_right.xml | 9 - .../launcher3/config/FlagOverrideRule.java | 93 ++-- .../config/FlagOverrideSampleTest.java | 10 +- .../launcher3/logging/FileLogTest.java | 31 +- .../model/BaseModelUpdateTaskTestCase.java | 13 +- .../model/CacheDataUpdatedTaskTest.java | 4 + .../model/DbDowngradeHelperTest.java | 4 +- .../PackageInstallStateChangedTaskTest.java | 5 +- .../launcher3/util/TestLauncherProvider.java | 2 +- .../launcher3/AbstractFloatingView.java | 4 +- .../launcher3/BaseDraggingActivity.java | 4 +- src/com/android/launcher3/BubbleTextView.java | 34 +- src/com/android/launcher3/DeviceProfile.java | 10 +- src/com/android/launcher3/Hotseat.java | 3 +- .../launcher3/InstallShortcutReceiver.java | 17 +- src/com/android/launcher3/Launcher.java | 28 +- .../android/launcher3/LauncherAppState.java | 65 ++- src/com/android/launcher3/LauncherModel.java | 118 ++-- .../android/launcher3/LauncherProvider.java | 54 +- .../LauncherProviderChangeListener.java | 11 + .../android/launcher3/LauncherRootView.java | 10 +- .../launcher3/LauncherStateManager.java | 15 + src/com/android/launcher3/PagedView.java | 22 +- src/com/android/launcher3/PromiseAppInfo.java | 8 +- .../launcher3/SecondaryDropTarget.java | 10 +- .../launcher3/SessionCommitReceiver.java | 17 +- src/com/android/launcher3/Utilities.java | 8 +- .../launcher3/WidgetPreviewLoader.java | 4 +- src/com/android/launcher3/Workspace.java | 12 +- .../android/launcher3/WorkspaceItemInfo.java | 2 +- .../allapps/AllAppsContainerView.java | 30 +- .../launcher3/allapps/DiscoveryBounce.java | 4 +- .../compat/AccessibilityManagerCompat.java | 23 +- .../launcher3/compat/LauncherAppsCompat.java | 93 ++++ .../compat/LauncherAppsCompatVL.java | 216 ++++++++ .../LauncherAppsCompatVO.java} | 70 ++- .../compat/LauncherAppsCompatVQ.java | 29 +- .../compat/PackageInstallerCompat.java | 118 ++++ .../compat/PackageInstallerCompatVL.java | 287 ++++++++++ .../ShortcutConfigActivityInfo.java | 67 +-- .../launcher3/config/FeatureFlags.java | 11 +- .../launcher3/dragndrop/AddItemActivity.java | 7 +- .../dragndrop/BaseItemDragListener.java | 9 +- .../launcher3/dragndrop/DragLayer.java | 3 +- .../PinShortcutRequestActivityInfo.java | 10 +- .../android/launcher3/folder/FolderIcon.java | 2 +- .../graphics/DragPreviewProvider.java | 7 - .../launcher3/graphics/DrawableFactory.java | 7 +- .../launcher3/icons/ComponentWithLabel.java | 9 +- .../android/launcher3/icons/IconCache.java | 28 +- .../launcher3/icons/LauncherIcons.java | 10 +- .../launcher3/icons/ShortcutCachingLogic.java | 67 +++ .../android/launcher3/logging/FileLog.java | 10 +- .../model/AddWorkspaceItemsTask.java | 8 +- .../android/launcher3/model/AllAppsList.java | 35 +- .../model/GridSizeMigrationTask.java | 10 +- .../android/launcher3/model/LoaderCursor.java | 8 +- .../android/launcher3/model/LoaderTask.java | 52 +- .../model/PackageInstallStateChangedTask.java | 10 +- .../launcher3/model/PackageUpdatedTask.java | 13 +- .../model/SdCardAvailableReceiver.java | 6 +- .../android/launcher3/model/WidgetItem.java | 2 +- .../notification/NotificationItemView.java | 4 +- .../launcher3/pm/InstallSessionTracker.java | 129 ----- .../launcher3/pm/PackageInstallInfo.java | 60 -- .../launcher3/pm/PackageInstallerCompat.java | 219 -------- .../popup/PopupContainerWithArrow.java | 8 - .../states/InternalStateHandler.java | 145 +++++ .../launcher3/states/RotationHelper.java | 5 +- .../testing/TestInformationHandler.java | 70 +-- .../launcher3/testing/TestProtocol.java | 10 +- .../launcher3/touch/ItemClickHandler.java | 4 +- .../touch/ItemLongClickListener.java | 13 - .../launcher3/touch/SwipeDetector.java | 279 +++++----- .../launcher3/util/ActivityTracker.java | 143 ----- .../launcher3/util/PackageManagerHelper.java | 54 +- .../util/SimpleBroadcastReceiver.java | 48 -- .../launcher3/util/UiThreadHelper.java | 13 +- .../launcher3/views/FloatingIconView.java | 13 +- .../android/launcher3/views/ScrimView.java | 1 - .../widget/PendingAddShortcutInfo.java | 2 +- .../android/launcher3/widget/WidgetCell.java | 12 +- .../widget/custom/CustomWidgetManager.java | 45 +- .../systemui/plugins/CustomWidgetPlugin.java | 17 + .../plugins/OverviewScreenshotActions.java | 41 -- .../systemui/plugins/RecentsExtraCard.java | 42 -- .../android/launcher3/model/WidgetsModel.java | 13 +- .../launcher3/uioverrides/UiFactory.java | 3 +- tests/AndroidManifest-common.xml | 12 +- tests/res/layout/test_layout_widget_list.xml | 20 - .../launcher3/compat/PromiseIconUiTest.java | 1 - .../launcher3/model/LoaderCursorTest.java | 55 +- .../launcher3/provider/RestoreDbTaskTest.java | 7 +- .../CustomShortcutConfigActivity.java | 66 --- .../testcomponent/ListViewService.java | 95 ---- .../testcomponent/TestCommandProvider.java | 131 ----- .../testcomponent/TestCommandReceiver.java | 105 +++- .../launcher3/touch/SwipeDetectorTest.java | 8 +- .../launcher3/ui/AbstractLauncherUiTest.java | 58 +- .../ui/DefaultLayoutProviderTest.java | 7 +- .../launcher3/ui/TaplTestsLauncher3.java | 16 - .../ui/widget/AddConfigWidgetTest.java | 6 +- .../launcher3/ui/widget/AddWidgetTest.java | 5 +- .../launcher3/ui/widget/BindWidgetTest.java | 71 ++- .../util/rule/TestStabilityRule.java | 122 ++-- .../com/android/launcher3/tapl/AllApps.java | 55 +- .../android/launcher3/tapl/Background.java | 48 +- .../android/launcher3/tapl/BaseOverview.java | 4 +- .../tapl/com/android/launcher3/tapl/Home.java | 6 - .../tapl/LauncherInstrumentation.java | 131 ++--- .../android/launcher3/tapl/TestHelpers.java | 20 +- .../com/android/launcher3/tapl/Widgets.java | 40 +- .../com/android/launcher3/tapl/Workspace.java | 12 +- 201 files changed, 4009 insertions(+), 5716 deletions(-) rename go/quickstep/src/com/android/quickstep/{FallbackActivityInterface.java => FallbackActivityControllerHelper.java} (85%) rename go/quickstep/src/com/android/quickstep/{GoActivityInterface.java => GoActivityControlHelper.java} (93%) rename go/quickstep/src/com/android/quickstep/{LauncherActivityInterface.java => LauncherActivityControllerHelper.java} (92%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/{FallbackActivityInterface.java => FallbackActivityControllerHelper.java} (93%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/{LauncherActivityInterface.java => LauncherActivityControllerHelper.java} (91%) rename quickstep/{src/com/android/quickstep/RecentsAnimationController.java => recents_ui_overrides/src/com/android/quickstep/RecentsAnimationWrapper.java} (58%) delete mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/ViewUtils.java rename quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/{AssistantInputConsumer.java => AssistantTouchConsumer.java} (78%) rename quickstep/{src/com/android/quickstep => recents_ui_overrides/src/com/android/quickstep/inputconsumers}/InputConsumer.java (95%) delete mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java rename quickstep/recents_ui_overrides/src/com/android/quickstep/util/{AppWindowAnimationHelper.java => ClipAnimationHelper.java} (88%) rename {src/com/android/launcher3 => quickstep/recents_ui_overrides/src/com/android/quickstep}/util/ObjectWrapper.java (96%) rename quickstep/{src/com/android/quickstep/RecentsAnimationCallbacks.java => recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java} (50%) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/util/SwipeAnimationTargetSet.java delete mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsExtraViewContainer.java rename quickstep/src/com/android/quickstep/{BaseActivityInterface.java => ActivityControlHelper.java} (87%) delete mode 100644 quickstep/src/com/android/quickstep/GestureState.java create mode 100644 quickstep/src/com/android/quickstep/OverviewInteractionState.java create mode 100644 quickstep/src/com/android/quickstep/RecentsActivityTracker.java delete mode 100644 quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java delete mode 100644 quickstep/src/com/android/quickstep/RecentsAnimationTargets.java delete mode 100644 quickstep/src/com/android/quickstep/SystemUiProxy.java delete mode 100644 quickstep/src/com/android/quickstep/util/ActivityInitListener.java rename quickstep/src/com/android/quickstep/{RemoteAnimationTargets.java => util/RemoteAnimationTargetSet.java} (87%) delete mode 100644 quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java delete mode 100644 res/anim/slide_in_right.xml create mode 100644 src/com/android/launcher3/LauncherProviderChangeListener.java create mode 100644 src/com/android/launcher3/compat/LauncherAppsCompat.java create mode 100644 src/com/android/launcher3/compat/LauncherAppsCompatVL.java rename src/com/android/launcher3/{pm/PinRequestHelper.java => compat/LauncherAppsCompatVO.java} (59%) rename quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java => src/com/android/launcher3/compat/LauncherAppsCompatVQ.java (51%) create mode 100644 src/com/android/launcher3/compat/PackageInstallerCompat.java create mode 100644 src/com/android/launcher3/compat/PackageInstallerCompatVL.java rename src/com/android/launcher3/{pm => compat}/ShortcutConfigActivityInfo.java (66%) create mode 100644 src/com/android/launcher3/icons/ShortcutCachingLogic.java delete mode 100644 src/com/android/launcher3/pm/InstallSessionTracker.java delete mode 100644 src/com/android/launcher3/pm/PackageInstallInfo.java delete mode 100644 src/com/android/launcher3/pm/PackageInstallerCompat.java create mode 100644 src/com/android/launcher3/states/InternalStateHandler.java delete mode 100644 src/com/android/launcher3/util/ActivityTracker.java delete mode 100644 src/com/android/launcher3/util/SimpleBroadcastReceiver.java delete mode 100644 src_plugins/com/android/systemui/plugins/OverviewScreenshotActions.java delete mode 100644 src_plugins/com/android/systemui/plugins/RecentsExtraCard.java delete mode 100644 tests/res/layout/test_layout_widget_list.xml delete mode 100644 tests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java delete mode 100644 tests/src/com/android/launcher3/testcomponent/ListViewService.java delete mode 100644 tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java diff --git a/Android.mk b/Android.mk index 3d1d996dfd..985612fbfb 100644 --- a/Android.mk +++ b/Android.mk @@ -145,7 +145,7 @@ LOCAL_USE_AAPT2 := true LOCAL_AAPT2_ONLY := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else @@ -216,7 +216,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else @@ -262,7 +262,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := optional -LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLibLauncherWrapper launcherprotosnano +LOCAL_STATIC_JAVA_LIBRARIES := SystemUISharedLib launcherprotosnano ifneq (,$(wildcard frameworks/base)) LOCAL_PRIVATE_PLATFORM_APIS := true else diff --git a/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java b/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java index 3953fd0279..bcb1f5c3b4 100644 --- a/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java +++ b/go/quickstep/src/com/android/launcher3/GoLauncherAppTransitionManagerImpl.java @@ -40,9 +40,7 @@ public final class GoLauncherAppTransitionManagerImpl extends QuickstepAppTransi @Override protected void composeRecentsLaunchAnimator(AnimatorSet anim, View v, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - boolean launcherClosing) { + RemoteAnimationTargetCompat[] targets, boolean launcherClosing) { // Stubbed. Recents launch animation will come from the recents view itself and will not // use remote animations. } @@ -76,23 +74,21 @@ public final class GoLauncherAppTransitionManagerImpl extends QuickstepAppTransi } @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, + public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, AnimationResult result) { boolean isGoingToRecents = - taskIsATargetWithMode(appTargets, mLauncher.getTaskId(), MODE_OPENING) + taskIsATargetWithMode(targetCompats, mLauncher.getTaskId(), MODE_OPENING) && (mLauncher.getStateManager().getState() == LauncherState.OVERVIEW); if (isGoingToRecents) { IconRecentsView recentsView = mLauncher.getOverviewPanel(); if (!recentsView.isReadyForRemoteAnim()) { recentsView.setOnReadyForRemoteAnimCallback(() -> - postAsyncCallback(mHandler, () -> onCreateAnimation(appTargets, - wallpaperTargets, result)) + postAsyncCallback(mHandler, () -> onCreateAnimation(targetCompats, result)) ); return; } } - super.onCreateAnimation(appTargets, wallpaperTargets, result); + super.onCreateAnimation(targetCompats, result); } } } diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index f2aa842d12..ae8fd82241 100644 --- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -89,5 +89,5 @@ public abstract class RecentsUiFactory { return RotationMode.NORMAL; } - public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { } + public static void clearSwipeSharedState(boolean finishAnimation) {} } diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java index 6b50088221..92900f2168 100644 --- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -32,6 +32,7 @@ import android.util.Log; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAnimationRunner; import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.IconRecentsView; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; @@ -46,12 +47,12 @@ final class AppToOverviewAnimationProvider imple RemoteAnimationProvider { private static final String TAG = "AppToOverviewAnimationProvider"; - private final BaseActivityInterface mHelper; + private final ActivityControlHelper mHelper; private final int mTargetTaskId; private IconRecentsView mRecentsView; private AppToOverviewAnimationListener mAnimationReadyListener; - AppToOverviewAnimationProvider(BaseActivityInterface helper, int targetTaskId) { + AppToOverviewAnimationProvider(ActivityControlHelper helper, int targetTaskId) { mHelper = helper; mTargetTaskId = targetTaskId; } @@ -75,7 +76,7 @@ final class AppToOverviewAnimationProvider imple if (mAnimationReadyListener != null) { mAnimationReadyListener.onActivityReady(activity); } - BaseActivityInterface.AnimationFactory factory = + ActivityControlHelper.AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible, false /* animate activity */, (controller) -> { controller.dispatchOnStart(); @@ -85,7 +86,7 @@ final class AppToOverviewAnimationProvider imple anim.start(); }); factory.onRemoteAnimationReceived(null); - factory.createActivityInterface(getRecentsLaunchDuration()); + factory.createActivityController(getRecentsLaunchDuration()); mRecentsView = activity.getOverviewPanel(); return false; } @@ -94,12 +95,11 @@ final class AppToOverviewAnimationProvider imple * Create remote window animation from the currently running app to the overview panel. Should * be called after {@link #onActivityReady}. * - * @param appTargets the target apps + * @param targetCompats the target apps * @return animation from app to overview */ @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { + public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) { if (mAnimationReadyListener != null) { mAnimationReadyListener.onWindowAnimationCreated(); } @@ -112,14 +112,14 @@ final class AppToOverviewAnimationProvider imple return anim; } - RemoteAnimationTargets targets = - new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING); - mRecentsView.setTransitionedFromApp(!targets.isAnimatingHome()); + RemoteAnimationTargetSet targetSet = + new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING); + mRecentsView.setTransitionedFromApp(!targetSet.isAnimatingHome()); RemoteAnimationTargetCompat recentsTarget = null; RemoteAnimationTargetCompat closingAppTarget = null; - for (RemoteAnimationTargetCompat target : appTargets) { + for (RemoteAnimationTargetCompat target : targetCompats) { if (target.mode == MODE_OPENING) { recentsTarget = target; } else if (target.mode == MODE_CLOSING && target.taskId == mTargetTaskId) { @@ -157,17 +157,16 @@ final class AppToOverviewAnimationProvider imple false /* startAtFrontOfQueue */) { @Override - public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, + public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats, AnimationResult result) { IconRecentsView recentsView = mRecentsView; if (!recentsView.isReadyForRemoteAnim()) { recentsView.setOnReadyForRemoteAnimCallback(() -> postAsyncCallback(handler, - () -> onCreateAnimation(appTargets, wallpaperTargets, result)) + () -> onCreateAnimation(targetCompats, result)) ); return; } - result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context); + result.setAnimation(createWindowAnimation(targetCompats), context); } }; return ActivityOptionsCompat.makeRemoteAnimation( diff --git a/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java similarity index 85% rename from go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java rename to go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java index 2af8441853..057b48bb2b 100644 --- a/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/go/quickstep/src/com/android/quickstep/FallbackActivityControllerHelper.java @@ -26,21 +26,21 @@ import androidx.annotation.Nullable; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.quickstep.util.ActivityInitListener; +import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.IconRecentsView; import java.util.function.BiPredicate; import java.util.function.Consumer; /** - * {@link BaseActivityInterface} for recents when the default launcher is different than the + * {@link ActivityControlHelper} for recents when the default launcher is different than the * currently running one and apps should interact with the {@link RecentsActivity} as opposed * to the in-launcher one. */ -public final class FallbackActivityInterface extends - GoActivityInterface { +public final class FallbackActivityControllerHelper extends + GoActivityControlHelper { - public FallbackActivityInterface() { } + public FallbackActivityControllerHelper() { } @Override public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible, @@ -58,17 +58,17 @@ public final class FallbackActivityInterface extends boolean isAnimatingToRecents = false; @Override - public void onRemoteAnimationReceived(RemoteAnimationTargets targets) { + public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { isAnimatingToRecents = targets != null && targets.isAnimatingHome(); if (!isAnimatingToRecents) { rv.setAlpha(1); } - createActivityInterface(getSwipeUpDestinationAndLength( + createActivityController(getSwipeUpDestinationAndLength( activity.getDeviceProfile(), activity, new Rect())); } @Override - public void createActivityInterface(long transitionLength) { + public void createActivityController(long transitionLength) { if (!isAnimatingToRecents) { return; } @@ -85,13 +85,13 @@ public final class FallbackActivityInterface extends @Override public ActivityInitListener createActivityInitListener( BiPredicate onInitListener) { - return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER); + return new RecentsActivityTracker(onInitListener); } @Nullable @Override public RecentsActivity getCreatedActivity() { - return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); + return RecentsActivityTracker.getCurrentActivity(); } @Nullable diff --git a/go/quickstep/src/com/android/quickstep/GoActivityInterface.java b/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java similarity index 93% rename from go/quickstep/src/com/android/quickstep/GoActivityInterface.java rename to go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java index 5ce0f4cdf5..274a347cbb 100644 --- a/go/quickstep/src/com/android/quickstep/GoActivityInterface.java +++ b/go/quickstep/src/com/android/quickstep/GoActivityControlHelper.java @@ -13,8 +13,8 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; * * @param activity that contains the overview */ -public abstract class GoActivityInterface implements - BaseActivityInterface { +public abstract class GoActivityControlHelper implements + ActivityControlHelper { @Override public void onTransitionCancelled(T activity, boolean activityVisible) { diff --git a/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java similarity index 92% rename from go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java rename to go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java index 5bff8e8060..b0d9cda6bc 100644 --- a/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/go/quickstep/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -30,10 +30,10 @@ import java.util.function.BiPredicate; import java.util.function.Consumer; /** - * {@link BaseActivityInterface} for the in-launcher recents. + * {@link ActivityControlHelper} for the in-launcher recents. * TODO: Implement the app to overview animation functionality */ -public final class LauncherActivityInterface extends GoActivityInterface { +public final class LauncherActivityControllerHelper extends GoActivityControlHelper { @Override public AnimationFactory prepareRecentsUI(Launcher activity, @@ -43,7 +43,8 @@ public final class LauncherActivityInterface extends GoActivityInterfacegetOverviewPanel().setUsingRemoteAnimation(true); //TODO: Implement this based off where the recents view needs to be for app => recents anim. return new AnimationFactory() { - public void createActivityInterface(long transitionLength) { + @Override + public void createActivityController(long transitionLength) { callback.accept(activity.getStateManager().createAnimationToNewWorkspace( fromState, OVERVIEW, transitionLength)); } @@ -54,7 +55,7 @@ public final class LauncherActivityInterface extends GoActivityInterface onInitListener) { return new LauncherInitListener(onInitListener); } diff --git a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index a436ce7033..216972cba2 100644 --- a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -27,8 +27,8 @@ import android.view.ViewConfiguration; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.quickstep.ActivityControlHelper.ActivityInitListener; import com.android.quickstep.AppToOverviewAnimationProvider.AppToOverviewAnimationListener; -import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.views.IconRecentsView; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.LatencyTrackerCompat; @@ -40,28 +40,26 @@ import com.android.systemui.shared.system.LatencyTrackerCompat; public class OverviewCommandHelper { private final Context mContext; - private final RecentsAnimationDeviceState mDeviceState; + private final ActivityManagerWrapper mAM; private final RecentsModel mRecentsModel; private final OverviewComponentObserver mOverviewComponentObserver; private long mLastToggleTime; - public OverviewCommandHelper(Context context, RecentsAnimationDeviceState deviceState, - OverviewComponentObserver observer) { + public OverviewCommandHelper(Context context, OverviewComponentObserver observer) { mContext = context; - mDeviceState = deviceState; + mAM = ActivityManagerWrapper.getInstance(); mRecentsModel = RecentsModel.INSTANCE.get(mContext); mOverviewComponentObserver = observer; } public void onOverviewToggle() { // If currently screen pinning, do not enter overview - if (mDeviceState.isScreenPinningActive()) { + if (mAM.isScreenPinningActive()) { return; } - ActivityManagerWrapper.getInstance() - .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); + mAM.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); MAIN_EXECUTOR.execute(new RecentsActivityCommand<>()); } @@ -101,15 +99,15 @@ public class OverviewCommandHelper { private class RecentsActivityCommand implements Runnable { - protected final BaseActivityInterface mHelper; + protected final ActivityControlHelper mHelper; private final long mCreateTime; private final long mToggleClickedTime = SystemClock.uptimeMillis(); private boolean mUserEventLogged; - private ActivityInitListener mListener; + private ActivityInitListener mListener; public RecentsActivityCommand() { - mHelper = mOverviewComponentObserver.getActivityInterface(); + mHelper = mOverviewComponentObserver.getActivityControlHelper(); mCreateTime = SystemClock.elapsedRealtime(); // Preload the plan diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java index f743663326..19dd82f7f7 100644 --- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -34,9 +34,6 @@ import android.view.MotionEvent; import com.android.launcher3.Utilities; import com.android.launcher3.compat.UserManagerCompat; -import com.android.launcher3.util.DefaultDisplay; -import com.android.quickstep.RecentsAnimationDeviceState; -import com.android.quickstep.SystemUiProxy; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; @@ -47,6 +44,15 @@ import com.android.systemui.shared.recents.ISystemUiProxy; public class TouchInteractionService extends Service { private static final String TAG = "GoTouchInteractionService"; + private boolean mIsUserUnlocked; + private BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { + initWhenUserUnlocked(); + } + } + }; private final IBinder mMyBinder = new IOverviewProxy.Stub() { @@ -57,26 +63,26 @@ public class TouchInteractionService extends Service { public void onInitialize(Bundle bundle) throws RemoteException { ISystemUiProxy iSystemUiProxy = ISystemUiProxy.Stub .asInterface(bundle.getBinder(KEY_EXTRA_SYSUI_PROXY)); - SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(iSystemUiProxy); + mRecentsModel.setSystemUiProxy(iSystemUiProxy); } @Override public void onOverviewToggle() { - if (mDeviceState.isUserUnlocked()) { + if (mIsUserUnlocked) { mOverviewCommandHelper.onOverviewToggle(); } } @Override public void onOverviewShown(boolean triggeredFromAltTab) { - if (mDeviceState.isUserUnlocked()) { + if (mIsUserUnlocked) { mOverviewCommandHelper.onOverviewShown(triggeredFromAltTab); } } @Override public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { - if (mDeviceState.isUserUnlocked() && triggeredFromAltTab && !triggeredFromHomeKey) { + if (mIsUserUnlocked && triggeredFromAltTab && !triggeredFromHomeKey) { // onOverviewShownFromAltTab hides the overview and ends at the target app mOverviewCommandHelper.onOverviewHidden(); } @@ -84,7 +90,7 @@ public class TouchInteractionService extends Service { @Override public void onTip(int actionType, int viewType) { - if (mDeviceState.isUserUnlocked()) { + if (mIsUserUnlocked) { mOverviewCommandHelper.onTip(actionType, viewType); } } @@ -121,7 +127,7 @@ public class TouchInteractionService extends Service { public void onMotionEvent(MotionEvent ev) { } public void onBind(ISystemUiProxy iSystemUiProxy) { - SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(iSystemUiProxy); + mRecentsModel.setSystemUiProxy(iSystemUiProxy); } }; @@ -134,30 +140,35 @@ public class TouchInteractionService extends Service { private RecentsModel mRecentsModel; private OverviewComponentObserver mOverviewComponentObserver; private OverviewCommandHelper mOverviewCommandHelper; - private RecentsAnimationDeviceState mDeviceState; @Override public void onCreate() { super.onCreate(); - mDeviceState = new RecentsAnimationDeviceState(this); - mDeviceState.runOnUserUnlocked(this::onUserUnlocked); + if (UserManagerCompat.getInstance(this).isUserUnlocked(Process.myUserHandle())) { + initWhenUserUnlocked(); + } else { + mIsUserUnlocked = false; + registerReceiver(mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); + } sConnected = true; } - public void onUserUnlocked() { + private void initWhenUserUnlocked() { mRecentsModel = RecentsModel.INSTANCE.get(this); - mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState); - mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState, + mOverviewComponentObserver = new OverviewComponentObserver(this); + mOverviewCommandHelper = new OverviewCommandHelper(this, mOverviewComponentObserver); + mIsUserUnlocked = true; + Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); } @Override public void onDestroy() { - if (mDeviceState.isUserUnlocked()) { + if (mIsUserUnlocked) { mOverviewComponentObserver.onDestroy(); } - mDeviceState.destroy(); + Utilities.unregisterReceiverSafely(this, mUserUnlockedReceiver); sConnected = false; super.onDestroy(); } diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java index 5c4f37ca98..e1b71a0b5f 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java @@ -22,7 +22,6 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Process; import android.os.UserHandle; - import androidx.annotation.NonNull; /** @@ -36,8 +35,6 @@ public class BaseIconFactory implements AutoCloseable { static final boolean ATLEAST_OREO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; - private static final float ICON_BADGE_SCALE = 0.444f; - private final Rect mOldBounds = new Rect(); protected final Context mContext; private final Canvas mCanvas; @@ -254,7 +251,7 @@ public class BaseIconFactory implements AutoCloseable { * Adds the {@param badge} on top of {@param target} using the badge dimensions. */ public void badgeWithDrawable(Canvas target, Drawable badge) { - int badgeSize = getBadgeSizeForIconSize(mIconBitmapSize); + int badgeSize = mContext.getResources().getDimensionPixelSize(R.dimen.profile_badge_size); badge.setBounds(mIconBitmapSize - badgeSize, mIconBitmapSize - badgeSize, mIconBitmapSize, mIconBitmapSize); badge.draw(target); @@ -334,13 +331,6 @@ public class BaseIconFactory implements AutoCloseable { iconDpi); } - /** - * Returns the correct badge size given an icon size - */ - public static int getBadgeSizeForIconSize(int iconSize) { - return (int) (ICON_BADGE_SCALE * iconSize); - } - /** * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size. * This allows the badging to be done based on the action bitmap size rather than diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java index 93f0538bd5..c100f05963 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java @@ -273,7 +273,7 @@ public abstract class BaseIconCache { if (entry.icon == null) return; entry.title = cachingLogic.getLabel(object); entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user); - if (cachingLogic.addToMemCache()) mCache.put(key, entry); + mCache.put(key, entry); ContentValues values = newContentValues(entry, entry.title.toString(), componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList)); @@ -312,12 +312,20 @@ public abstract class BaseIconCache { @NonNull ComponentName componentName, @NonNull UserHandle user, @NonNull Supplier infoProvider, @NonNull CachingLogic cachingLogic, boolean usePackageIcon, boolean useLowResIcon) { + return cacheLocked(componentName, user, infoProvider, cachingLogic, usePackageIcon, + useLowResIcon, true); + } + + protected CacheEntry cacheLocked( + @NonNull ComponentName componentName, @NonNull UserHandle user, + @NonNull Supplier infoProvider, @NonNull CachingLogic cachingLogic, + boolean usePackageIcon, boolean useLowResIcon, boolean addToMemCache) { assertWorkerThread(); ComponentKey cacheKey = new ComponentKey(componentName, user); CacheEntry entry = mCache.get(cacheKey); if (entry == null || (entry.isLowRes() && !useLowResIcon)) { entry = new CacheEntry(); - if (cachingLogic.addToMemCache()) { + if (addToMemCache) { mCache.put(cacheKey, entry); } @@ -374,7 +382,7 @@ public abstract class BaseIconCache { * Adds a default package entry in the cache. This entry is not persisted and will be removed * when the cache is flushed. */ - protected synchronized void cachePackageInstallInfo(String packageName, UserHandle user, + public synchronized void cachePackageInstallInfo(String packageName, UserHandle user, Bitmap icon, CharSequence title) { removeFromMemCacheLocked(packageName, user); diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index e40a9c2c96..16bc7ae834 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -17,6 +17,7 @@ package com.android.launcher3.icons.cache; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageInfo; import android.os.LocaleList; import android.os.UserHandle; @@ -43,9 +44,9 @@ public interface CachingLogic { } /** - * Returns true the object should be added to mem cache; otherwise returns false. + * Returns the timestamp the entry was last updated in cache. */ - default boolean addToMemCache() { - return true; + default long getLastUpdatedTime(T object, PackageInfo info) { + return info.lastUpdateTime; } } diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java index 8224966d87..bcdbce5e29 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java @@ -171,7 +171,8 @@ public class IconCacheUpdateHandler { long updateTime = c.getLong(indexLastUpdate); int version = c.getInt(indexVersion); T app = componentMap.remove(component); - if (version == info.versionCode && updateTime == info.lastUpdateTime + if (version == info.versionCode + && updateTime == cachingLogic.getLastUpdatedTime(app, info) && TextUtils.equals(c.getString(systemStateIndex), mIconCache.getIconSystemState(info.packageName))) { @@ -231,7 +232,6 @@ public class IconCacheUpdateHandler { } } - /** * A runnable that updates invalid icons and adds missing icons in the DB for the provided * LauncherActivityInfo list. Items are updated/added one at a time, so that the diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index d84248419e..711594386f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -30,17 +30,17 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.view.View; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.SpringAnimationBuilder; -import com.android.quickstep.util.AppWindowAnimationHelper; +import com.android.quickstep.util.ClipAnimationHelper; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + /** * A {@link QuickstepAppTransitionManagerImpl} that also implements recents transitions from * {@link RecentsView}. @@ -64,16 +64,15 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti @Override protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, - @NonNull RemoteAnimationTargetCompat[] appTargets, - @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) { + @NonNull RemoteAnimationTargetCompat[] targets, boolean launcherClosing) { RecentsView recentsView = mLauncher.getOverviewPanel(); boolean skipLauncherChanges = !launcherClosing; - TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets); + TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); - AppWindowAnimationHelper helper = new AppWindowAnimationHelper(mLauncher); - anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, - wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION)); + ClipAnimationHelper helper = new ClipAnimationHelper(mLauncher); + anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets, helper) + .setDuration(RECENTS_LAUNCH_DURATION)); Animator childStateAnimation = null; // Found a visible recents task that matches the opening app, lets launch the app from there diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java index 76050d57bd..c5c4add6b2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherInitListenerEx.java @@ -27,7 +27,7 @@ public class LauncherInitListenerEx extends LauncherInitListener { } @Override - public boolean init(Launcher launcher, boolean alreadyOnHome) { + protected boolean init(Launcher launcher, boolean alreadyOnHome) { PredictionUiStateManager.INSTANCE.get(launcher).switchClient(Client.OVERVIEW); return super.init(launcher, alreadyOnHome); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java index 4c04b29598..8597f98390 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java @@ -18,7 +18,6 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import android.content.Context; @@ -49,8 +48,8 @@ import com.android.quickstep.RecentsModel; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.TouchInteractionService; -import com.android.quickstep.SystemUiProxy; import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.recents.ISystemUiProxy; import java.util.ArrayList; @@ -59,16 +58,21 @@ import java.util.ArrayList; */ public abstract class RecentsUiFactory { - private static final String TAG = RecentsUiFactory.class.getSimpleName(); - public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false; - /** - * Reusable command for applying the shelf height on the background thread. - */ - public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) -> { - SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2); - }; + private static final String TAG = RecentsUiFactory.class.getSimpleName(); + + private static AsyncCommand newSetShelfHeightCmd(Context context) { + return (visible, height) -> { + ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(context).getSystemUiProxy(); + if (sysUiProxy == null) return; + try { + sysUiProxy.setShelfHeight(visible != 0, height); + } catch (RemoteException e) { + Log.e(TAG, "Error setShelfHeight", e); + } + }; + } public static RotationMode ROTATION_LANDSCAPE = new RotationMode(-90) { @Override @@ -191,15 +195,11 @@ public abstract class RecentsUiFactory { return new RecentsViewStateController(launcher); } - /** Clears the swipe shared state for the current swipe gesture. */ - public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - launcher.getOverviewPanel().switchToScreenshot( - () -> TouchInteractionService.getSwipeSharedState().clearAllState( - finishAnimation)); - } else { - TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation); - } + /** + * Clears the swipe shared state for the current swipe gesture. + */ + public static void clearSwipeSharedState(boolean finishAnimation) { + TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation); } /** @@ -212,8 +212,9 @@ public abstract class RecentsUiFactory { DeviceProfile profile = launcher.getDeviceProfile(); boolean visible = (state == NORMAL || state == OVERVIEW) && launcher.isUserActive() && !profile.isVerticalBarLayout(); - UiThreadHelper.runAsyncCommand(launcher, SET_SHELF_HEIGHT, visible ? 1 : 0, - profile.hotseatBarSizePx); + UiThreadHelper.runAsyncCommand(launcher, newSetShelfHeightCmd(launcher), + visible ? 1 : 0, profile.hotseatBarSizePx); + if (state == NORMAL) { launcher.getOverviewPanel().setSwipeDownShouldLaunchApp(false); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index e4e60a04b1..468b8afc97 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -78,7 +78,7 @@ public class BackgroundAppState extends OverviewState { } else { dummyTask = recentsView.getTaskViewAt(0); } - return recentsView.getTempAppWindowAnimationHelper().updateForFullscreenOverview(dummyTask) + return recentsView.getTempClipAnimationHelper().updateForFullscreenOverview(dummyTask) .getScaleAndTranslation(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java index ee2e9519e5..4a3ad1d721 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java @@ -32,8 +32,8 @@ import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_TRANSLATE; import static com.android.launcher3.anim.Interpolators.ACCEL; -import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; +import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; @@ -50,7 +50,7 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; -import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.views.RecentsView; @@ -120,7 +120,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { * having it as part of the existing animation to the target state. */ private boolean handlingOverviewAnim() { - int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags(); + int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags(); return mStartState == NORMAL && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0; } @@ -132,33 +132,16 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { // Fade in prediction icons quickly, then rest of all apps after reaching overview. float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher) - OVERVIEW.getVerticalProgress(mLauncher); - builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress( - ACCEL, - 0, - ALL_APPS_CONTENT_FADE_THRESHOLD)); - builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress( - ACCEL, - progressToReachOverview, - progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD)); + builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress(ACCEL, + 0, ALL_APPS_CONTENT_FADE_THRESHOLD)); + builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(LINEAR, + progressToReachOverview, 1)); // Get workspace out of the way quickly, to prepare for potential pause. builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3); builder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, DEACCEL_3); builder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_3); return builder; - } else if (fromState == ALL_APPS && toState == NORMAL) { - AnimatorSetBuilder builder = new AnimatorSetBuilder(); - // Keep all apps/predictions opaque until the very end of the transition. - float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher); - builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress( - DEACCEL, - progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD, - progressToReachOverview)); - builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress( - DEACCEL, - 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, - 1)); - return builder; } return super.getAnimatorSetBuilderForStates(fromState, toState); } @@ -181,7 +164,6 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { AnimatorSetBuilder builder = new AnimatorSetBuilder(); builder.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2); - builder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3); if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) { builder.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2); builder.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2); 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 5c3b55d6c4..6576ec5737 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 @@ -45,9 +45,9 @@ import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.quickstep.SystemUiProxy; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -82,7 +82,7 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { - int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags(); + int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags(); if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) { return NORMAL; } 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 8a11ac80aa..ad90e1686e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -30,8 +30,9 @@ import android.view.View; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.quickstep.util.AppWindowAnimationHelper; +import com.android.quickstep.util.ClipAnimationHelper; import com.android.quickstep.util.RemoteAnimationProvider; +import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; @@ -48,14 +49,14 @@ final class AppToOverviewAnimationProvider imple private static final long RECENTS_LAUNCH_DURATION = 250; private static final String TAG = "AppToOverviewAnimationProvider"; - private final BaseActivityInterface mHelper; + private final ActivityControlHelper mHelper; // The id of the currently running task that is transitioning to overview. private final int mTargetTaskId; private T mActivity; private RecentsView mRecentsView; - AppToOverviewAnimationProvider(BaseActivityInterface helper, int targetTaskId) { + AppToOverviewAnimationProvider(ActivityControlHelper helper, int targetTaskId) { mHelper = helper; mTargetTaskId = targetTaskId; } @@ -69,7 +70,7 @@ final class AppToOverviewAnimationProvider imple boolean onActivityReady(T activity, Boolean wasVisible) { activity.getOverviewPanel().showCurrentTask(mTargetTaskId); AbstractFloatingView.closeAllOpenViews(activity, wasVisible); - BaseActivityInterface.AnimationFactory factory = + ActivityControlHelper.AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible, false /* animate activity */, (controller) -> { controller.dispatchOnStart(); @@ -79,7 +80,7 @@ final class AppToOverviewAnimationProvider imple anim.start(); }); factory.onRemoteAnimationReceived(null); - factory.createActivityInterface(RECENTS_LAUNCH_DURATION); + factory.createActivityController(RECENTS_LAUNCH_DURATION); factory.setRecentsAttachedToAppWindow(true, false); mActivity = activity; mRecentsView = mActivity.getOverviewPanel(); @@ -89,12 +90,11 @@ final class AppToOverviewAnimationProvider imple /** * Create remote window animation from the currently running app to the overview panel. * - * @param appTargets the target apps + * @param targetCompats the target apps * @return animation from app to overview */ @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { + public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) { if (mRecentsView != null) { mRecentsView.setRunningTaskIconScaledDown(true); } @@ -114,18 +114,18 @@ final class AppToOverviewAnimationProvider imple return anim; } - RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, - wallpaperTargets, MODE_CLOSING); + RemoteAnimationTargetSet targetSet = + new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING); // Use the top closing app to determine the insets for the animation - RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId); + RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mTargetTaskId); if (runningTaskTarget == null) { Log.e(TAG, "No closing app"); anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION)); return anim; } - final AppWindowAnimationHelper clipHelper = new AppWindowAnimationHelper(mActivity); + final ClipAnimationHelper clipHelper = new ClipAnimationHelper(mActivity); // At this point, the activity is already started and laid-out. Get the home-bounds // relative to the screen using the rootView of the activity. @@ -141,22 +141,20 @@ final class AppToOverviewAnimationProvider imple clipHelper.updateTargetRect(targetRect); clipHelper.prepareAnimation(mActivity.getDeviceProfile(), false /* isOpening */); - AppWindowAnimationHelper.TransformParams params = new AppWindowAnimationHelper.TransformParams() + ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams() .setSyncTransactionApplier(new SyncRtSurfaceTransactionApplierCompat(rootView)); ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(RECENTS_LAUNCH_DURATION); valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR); valueAnimator.addUpdateListener((v) -> { - params.setProgress((float) v.getAnimatedValue()) - .setTargetSet(targets) - .setLauncherOnTop(true); - clipHelper.applyTransform(params); + params.setProgress((float) v.getAnimatedValue()); + clipHelper.applyTransform(targetSet, params); }); - if (targets.isAnimatingHome()) { + if (targetSet.isAnimatingHome()) { // If we are animating home, fade in the opening targets - RemoteAnimationTargets openingSet = new RemoteAnimationTargets(appTargets, - wallpaperTargets, MODE_OPENING); + RemoteAnimationTargetSet openingSet = + new RemoteAnimationTargetSet(targetCompats, MODE_OPENING); TransactionCompat transaction = new TransactionCompat(); valueAnimator.addUpdateListener((v) -> { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index e1e994c6a6..7196f7c6f3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -25,6 +25,7 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; +import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG; import android.animation.Animator; import android.annotation.TargetApi; @@ -56,22 +57,22 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.views.FloatingIconView; -import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; +import com.android.quickstep.ActivityControlHelper.ActivityInitListener; +import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.quickstep.util.ActiveGestureLog; -import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.AppWindowAnimationHelper; -import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; +import com.android.quickstep.inputconsumers.InputConsumer; +import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.ClipAnimationHelper.TransformParams; import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; +import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.SwipeAnimationTargetSet; +import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; -import java.util.ArrayList; import java.util.function.Consumer; /** @@ -79,7 +80,7 @@ import java.util.function.Consumer; */ @TargetApi(Build.VERSION_CODES.Q) public abstract class BaseSwipeUpHandler - implements RecentsAnimationListener { + implements SwipeAnimationListener { private static final String TAG = "BaseSwipeUpHandler"; protected static final Rect TEMP_RECT = new Rect(); @@ -97,11 +98,11 @@ public abstract class BaseSwipeUpHandler mActivityInterface; + protected final ActivityControlHelper mActivityControlHelper; protected final RecentsModel mRecentsModel; protected final int mRunningTaskId; - protected final AppWindowAnimationHelper mAppWindowAnimationHelper; + protected final ClipAnimationHelper mClipAnimationHelper; protected final TransformParams mTransformParams = new TransformParams(); private final Vibrator mVibrator; @@ -114,13 +115,7 @@ public abstract class BaseSwipeUpHandler mRecentsAnimationStartCallbacks = new ArrayList<>(); + protected final RecentsAnimationWrapper mRecentsAnimationWrapper; protected T mActivity; protected Q mRecentsView; @@ -135,20 +130,21 @@ public abstract class BaseSwipeUpHandler { mTransformParams.setSyncTransactionApplier(applier); - runOnRecentsAnimationStart(() -> - mRecentsAnimationTargets.addDependentTransactionApplier(applier)); + mRecentsAnimationWrapper.runOnInit(() -> + mRecentsAnimationWrapper.targetSet.addDependentTransactionApplier(applier)); }); mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> { @@ -223,10 +219,8 @@ public abstract class BaseSwipeUpHandler - mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController, - mRecentsAnimationTargets)); + mRecentsView.setRecentsAnimationWrapper(mRecentsAnimationWrapper); + mRecentsView.setClipAnimationHelper(mClipAnimationHelper); } protected void startNewTask(int successStateFlag, Consumer resultCallback) { @@ -238,7 +232,7 @@ public abstract class BaseSwipeUpHandler { + mRecentsAnimationWrapper.finish(true /* toRecents */, () -> { if (!mCanceled) { TaskView nextTask = mRecentsView.getTaskView(taskId); if (nextTask != null) { @@ -246,10 +240,10 @@ public abstract class BaseSwipeUpHandler { resultCallback.accept(success); if (!success) { - mActivityInterface.onLaunchTaskFailed(mActivity); + mActivityControlHelper.onLaunchTaskFailed(mActivity); nextTask.notifyTaskLaunchFailed(TAG); } else { - mActivityInterface.onLaunchTaskSuccess(mActivity); + mActivityControlHelper.onLaunchTaskSuccess(mActivity); } }, mMainThreadHandler); } @@ -259,40 +253,18 @@ public abstract class BaseSwipeUpHandler(mRecentsAnimationStartCallbacks)) { - action.run(); - } - mRecentsAnimationStartCallbacks.clear(); - } - } - - @Override - public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - mRecentsAnimationController = null; - mRecentsAnimationTargets = null; - } - - @Override - public void onRecentsAnimationFinished(RecentsAnimationController controller) { - mRecentsAnimationController = null; - mRecentsAnimationTargets = null; + mRecentsAnimationWrapper.setController(targetSet); } private Rect getStackBounds(DeviceProfile dp) { @@ -345,16 +299,16 @@ public abstract class BaseSwipeUpHandler { +public final class FallbackActivityControllerHelper implements + ActivityControlHelper { - public FallbackActivityInterface() { } + public FallbackActivityControllerHelper() { } @Override public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) { @@ -137,17 +137,17 @@ public final class FallbackActivityInterface implements boolean isAnimatingToRecents = false; @Override - public void onRemoteAnimationReceived(RemoteAnimationTargets targets) { + public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { isAnimatingToRecents = targets != null && targets.isAnimatingHome(); if (!isAnimatingToRecents) { rv.setContentAlpha(1); } - createActivityInterface(getSwipeUpDestinationAndLength( + createActivityController(getSwipeUpDestinationAndLength( activity.getDeviceProfile(), activity, new Rect())); } @Override - public void createActivityInterface(long transitionLength) { + public void createActivityController(long transitionLength) { AnimatorSet animatorSet = new AnimatorSet(); if (isAnimatingToRecents) { ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1); @@ -177,13 +177,13 @@ public final class FallbackActivityInterface implements @Override public ActivityInitListener createActivityInitListener( BiPredicate onInitListener) { - return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER); + return new RecentsActivityTracker(onInitListener); } @Nullable @Override public RecentsActivity getCreatedActivity() { - return BaseRecentsActivity.ACTIVITY_TRACKER.getCreatedActivity(); + return RecentsActivityTracker.getCurrentActivity(); } @Nullable diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java similarity index 91% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java rename to quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index f6b3654e69..bbcd3b42db 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -38,6 +38,7 @@ import android.animation.TimeInterpolator; import android.content.Context; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Region; import android.os.UserHandle; import android.view.MotionEvent; import android.view.View; @@ -49,6 +50,7 @@ import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherInitListenerEx; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; @@ -59,23 +61,21 @@ import com.android.launcher3.uioverrides.states.OverviewState; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.SysUINavigationMode.Mode; -import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.plugins.shared.LauncherOverlayManager; -import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.BiPredicate; import java.util.function.Consumer; /** - * {@link BaseActivityInterface} for the in-launcher recents. + * {@link ActivityControlHelper} for the in-launcher recents. */ -public final class LauncherActivityInterface implements BaseActivityInterface { +public final class LauncherActivityControllerHelper implements ActivityControlHelper { private Runnable mAdjustInterpolatorsRunnable; @@ -109,14 +109,6 @@ public final class LauncherActivityInterface implements BaseActivityInterface - - - - - - - - diff --git a/tests/res/layout/test_layout_widget_list.xml b/tests/res/layout/test_layout_widget_list.xml deleted file mode 100644 index 0152040f7e..0000000000 --- a/tests/res/layout/test_layout_widget_list.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java index efbd9c99c3..7ef946d4c4 100644 --- a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java +++ b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java @@ -48,7 +48,6 @@ public class PromiseIconUiTest extends AbstractLauncherUiTest { public void setUp() throws Exception { super.setUp(); mDevice.pressHome(); - waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null); waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL); mSessionId = -1; } diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 7029ad586c..64df8e0e95 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -1,5 +1,29 @@ package com.android.launcher3.model; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.database.MatrixCursor; +import android.graphics.Bitmap; +import android.os.Process; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.icons.IconCache; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.util.PackageManagerHelper; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static com.android.launcher3.LauncherSettings.Favorites.INTENT; import static com.android.launcher3.LauncherSettings.Favorites.CELLX; import static com.android.launcher3.LauncherSettings.Favorites.CELLY; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER; @@ -8,7 +32,6 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT import static com.android.launcher3.LauncherSettings.Favorites.ICON; import static com.android.launcher3.LauncherSettings.Favorites.ICON_PACKAGE; import static com.android.launcher3.LauncherSettings.Favorites.ICON_RESOURCE; -import static com.android.launcher3.LauncherSettings.Favorites.INTENT; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; @@ -17,41 +40,15 @@ import static com.android.launcher3.LauncherSettings.Favorites.RESTORED; import static com.android.launcher3.LauncherSettings.Favorites.SCREEN; import static com.android.launcher3.LauncherSettings.Favorites.TITLE; import static com.android.launcher3.LauncherSettings.Favorites._ID; - import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; - import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.LauncherApps; -import android.database.MatrixCursor; -import android.graphics.Bitmap; -import android.os.Process; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.icons.IconCache; -import com.android.launcher3.util.PackageManagerHelper; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - /** * Tests for {@link LoaderCursor} */ @@ -65,7 +62,7 @@ public class LoaderCursorTest { private MatrixCursor mCursor; private InvariantDeviceProfile mIDP; private Context mContext; - private LauncherApps mLauncherApps; + private LauncherAppsCompat mLauncherApps; private LoaderCursor mLoaderCursor; @@ -84,7 +81,7 @@ public class LoaderCursorTest { when(mMockApp.getIconCache()).thenReturn(mMockIconCache); when(mMockApp.getInvariantDeviceProfile()).thenReturn(mIDP); when(mMockApp.getContext()).thenReturn(mContext); - mLauncherApps = mContext.getSystemService(LauncherApps.class); + mLauncherApps = LauncherAppsCompat.getInstance(mContext); mLoaderCursor = new LoaderCursor(mCursor, mMockApp); mLoaderCursor.allUsers.put(0, Process.myUserHandle()); diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java index 27990f4305..6fa8d62a17 100644 --- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java @@ -1,11 +1,8 @@ package com.android.launcher3.provider; -import static org.junit.Assert.assertEquals; - import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; - import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; @@ -16,6 +13,8 @@ import com.android.launcher3.LauncherSettings.Favorites; import org.junit.Test; import org.junit.runner.RunWith; +import static org.junit.Assert.assertEquals; + /** * Tests for {@link RestoreDbTask} */ @@ -83,7 +82,7 @@ public class RestoreDbTaskTest { private final long mProfileId; MyDatabaseHelper(long profileId) { - super(InstrumentationRegistry.getContext(), null); + super(InstrumentationRegistry.getContext(), null, null); mProfileId = profileId; } diff --git a/tests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java b/tests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java deleted file mode 100644 index b673faa6f3..0000000000 --- a/tests/src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.testcomponent; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.ShortcutInfo; -import android.content.pm.ShortcutManager; -import android.graphics.drawable.Icon; -import android.os.Bundle; - -import com.android.launcher3.R; - -import java.util.UUID; - -/** - * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it. - * Custom shortcuts are replaced by deep shortcuts after api 25. - */ -public class CustomShortcutConfigActivity extends BaseTestingActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent launchIntent = new Intent(this, BaseTestingActivity.class) - .setAction("com.android.launcher3.intent.action.test_shortcut"); - Intent shortcutIntent = createShortcutResultIntent( - this, UUID.randomUUID().toString(), "Shortcut", - R.drawable.ic_widget, launchIntent); - setResult(RESULT_OK, shortcutIntent); - finish(); - } - - private static Intent createShortcutResultIntent( - Context context, String uniqueId, String name, int iconId, Intent launchIntent) { - ShortcutInfo shortcutInfo = - createShortcutInfo(context, uniqueId, name, iconId, launchIntent); - ShortcutManager sm = context.getSystemService(ShortcutManager.class); - return sm.createShortcutResultIntent(shortcutInfo); - } - - private static ShortcutInfo createShortcutInfo( - Context context, String uniqueId, String name, int iconId, Intent launchIntent) { - return new ShortcutInfo.Builder(context, uniqueId) - .setShortLabel(name) - .setLongLabel(name) - .setIcon(Icon.createWithResource(context, iconId)) - .setIntent(launchIntent) - .build(); - } -} diff --git a/tests/src/com/android/launcher3/testcomponent/ListViewService.java b/tests/src/com/android/launcher3/testcomponent/ListViewService.java deleted file mode 100644 index 3da20e0991..0000000000 --- a/tests/src/com/android/launcher3/testcomponent/ListViewService.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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.testcomponent; - -import android.content.Intent; -import android.os.IBinder; -import android.widget.RemoteViews; -import android.widget.RemoteViewsService; - -public class ListViewService extends RemoteViewsService { - - public static IBinder sBinderForTest; - - @Override - public RemoteViewsFactory onGetViewFactory(Intent intent) { - return new SimpleViewsFactory(); - } - - @Override - public IBinder onBind(Intent intent) { - return sBinderForTest != null ? sBinderForTest : super.onBind(intent); - } - - public static class SimpleViewsFactory implements RemoteViewsFactory { - - public int viewCount = 0; - - @Override - public void onCreate() { } - - @Override - public void onDataSetChanged() { } - - @Override - public void onDestroy() { } - - @Override - public int getCount() { - return viewCount; - } - - @Override - public RemoteViews getViewAt(int i) { - RemoteViews views = new RemoteViews("android", android.R.layout.simple_list_item_1); - views.setTextViewText(android.R.id.text1, getLabel(i)); - return views; - } - - public String getLabel(int i) { - return "Item " + i; - } - - @Override - public RemoteViews getLoadingView() { - return null; - } - - @Override - public int getViewTypeCount() { - return 1; - } - - @Override - public long getItemId(int i) { - return i; - } - - @Override - public boolean hasStableIds() { - return false; - } - - public IBinder toBinder() { - return new RemoteViewsService() { - @Override - public RemoteViewsFactory onGetViewFactory(Intent intent) { - return SimpleViewsFactory.this; - } - }.onBind(new Intent("dummy_intent")); - } - } -} diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java b/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java deleted file mode 100644 index f9981a9bfe..0000000000 --- a/tests/src/com/android/launcher3/testcomponent/TestCommandProvider.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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.testcomponent; - -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; -import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.DONT_KILL_APP; -import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; - -import static com.android.launcher3.testcomponent.TestCommandReceiver.DISABLE_TEST_LAUNCHER; -import static com.android.launcher3.testcomponent.TestCommandReceiver.ENABLE_TEST_LAUNCHER; -import static com.android.launcher3.testcomponent.TestCommandReceiver.EXTRA_VALUE; -import static com.android.launcher3.testcomponent.TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE; -import static com.android.launcher3.testcomponent.TestCommandReceiver.KILL_PROCESS; -import static com.android.launcher3.testcomponent.TestCommandReceiver.SET_LIST_VIEW_SERVICE_BINDER; - -import android.app.Activity; -import android.app.ActivityManager; -import android.content.ComponentName; -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.ParcelFileDescriptor; -import android.util.Base64; - -import com.android.launcher3.tapl.TestHelpers; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; - -public class TestCommandProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return true; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public String getType(Uri uri) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - throw new UnsupportedOperationException("unimplemented mock method"); - } - - @Override - public Bundle call(String method, String arg, Bundle extras) { - switch (method) { - case ENABLE_TEST_LAUNCHER: { - getContext().getPackageManager().setComponentEnabledSetting( - new ComponentName(getContext(), TestLauncherActivity.class), - COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP); - return null; - } - case DISABLE_TEST_LAUNCHER: { - getContext().getPackageManager().setComponentEnabledSetting( - new ComponentName(getContext(), TestLauncherActivity.class), - COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP); - return null; - } - case KILL_PROCESS: { - ((ActivityManager) getContext().getSystemService(Activity.ACTIVITY_SERVICE)) - .killBackgroundProcesses(arg); - return null; - } - - case GET_SYSTEM_HEALTH_MESSAGE: { - final Bundle response = new Bundle(); - response.putString("result", - TestHelpers.getSystemHealthMessage(getContext(), Long.parseLong(arg))); - return response; - } - - case SET_LIST_VIEW_SERVICE_BINDER: { - ListViewService.sBinderForTest = extras.getBinder(EXTRA_VALUE); - return null; - } - } - return super.call(method, arg, extras); - } - - @Override - public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - String path = Base64.encodeToString(uri.getPath().getBytes(), - Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP); - File file = new File(getContext().getCacheDir(), path); - if (!file.exists()) { - // Create an empty file so that we can pass its descriptor - try { - file.createNewFile(); - } catch (IOException e) { - } - } - - return ParcelFileDescriptor.open(file, MODE_READ_WRITE); - } -} diff --git a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java index eb6c3ed783..6a6916eec3 100644 --- a/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java +++ b/tests/src/com/android/launcher3/testcomponent/TestCommandReceiver.java @@ -15,36 +15,125 @@ */ package com.android.launcher3.testcomponent; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; +import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import static android.content.pm.PackageManager.DONT_KILL_APP; +import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; + +import android.app.Activity; +import android.app.ActivityManager; import android.app.Instrumentation; +import android.content.ComponentName; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.util.Base64; import androidx.test.InstrumentationRegistry; +import com.android.launcher3.tapl.TestHelpers; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + /** * Content provider to receive commands from tests */ -public class TestCommandReceiver { +public class TestCommandReceiver extends ContentProvider { public static final String ENABLE_TEST_LAUNCHER = "enable-test-launcher"; public static final String DISABLE_TEST_LAUNCHER = "disable-test-launcher"; public static final String KILL_PROCESS = "kill-process"; public static final String GET_SYSTEM_HEALTH_MESSAGE = "get-system-health-message"; - public static final String SET_LIST_VIEW_SERVICE_BINDER = "set-list-view-service-binder"; - public static final String EXTRA_VALUE = "value"; + @Override + public boolean onCreate() { + return true; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public String getType(Uri uri) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("unimplemented mock method"); + } + + @Override + public Bundle call(String method, String arg, Bundle extras) { + switch (method) { + case ENABLE_TEST_LAUNCHER: { + getContext().getPackageManager().setComponentEnabledSetting( + new ComponentName(getContext(), TestLauncherActivity.class), + COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP); + return null; + } + case DISABLE_TEST_LAUNCHER: { + getContext().getPackageManager().setComponentEnabledSetting( + new ComponentName(getContext(), TestLauncherActivity.class), + COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP); + return null; + } + case KILL_PROCESS: { + ((ActivityManager) getContext().getSystemService(Activity.ACTIVITY_SERVICE)). + killBackgroundProcesses(arg); + return null; + } + + case GET_SYSTEM_HEALTH_MESSAGE: { + final Bundle response = new Bundle(); + response.putString("result", TestHelpers.getSystemHealthMessage(getContext())); + return response; + } + } + return super.call(method, arg, extras); + } public static Bundle callCommand(String command) { return callCommand(command, null); } public static Bundle callCommand(String command, String arg) { - return callCommand(command, arg, null); - } - - public static Bundle callCommand(String command, String arg, Bundle extras) { Instrumentation inst = InstrumentationRegistry.getInstrumentation(); Uri uri = Uri.parse("content://" + inst.getContext().getPackageName() + ".commands"); - return inst.getTargetContext().getContentResolver().call(uri, command, arg, extras); + return inst.getTargetContext().getContentResolver().call(uri, command, arg, null); + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + String path = Base64.encodeToString(uri.getPath().getBytes(), + Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP); + File file = new File(getContext().getCacheDir(), path); + if (!file.exists()) { + // Create an empty file so that we can pass its descriptor + try { + file.createNewFile(); + } catch (IOException e) { + } + } + + return ParcelFileDescriptor.open(file, MODE_READ_WRITE); } } diff --git a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java index f209fae976..e042357083 100644 --- a/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java +++ b/tests/src/com/android/launcher3/touch/SwipeDetectorTest.java @@ -25,10 +25,6 @@ import static org.mockito.Mockito.verify; import android.util.Log; import android.view.ViewConfiguration; -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - import com.android.launcher3.testcomponent.TouchEventGenerator; import org.junit.Before; @@ -37,6 +33,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + @SmallTest @RunWith(AndroidJUnit4.class) public class SwipeDetectorTest { diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 62989a30ef..1fac7081b7 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -17,7 +17,6 @@ package com.android.launcher3.ui; import static androidx.test.InstrumentationRegistry.getInstrumentation; -import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; import static com.android.launcher3.tapl.LauncherInstrumentation.ContainerType; import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -28,13 +27,11 @@ import static java.lang.System.exit; import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.LauncherActivityInfo; -import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.os.Process; import android.os.RemoteException; @@ -46,19 +43,19 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.Until; -import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.Utilities; +import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.tapl.TestHelpers; import com.android.launcher3.testcomponent.TestCommandReceiver; import com.android.launcher3.testing.TestProtocol; -import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.LooperExecutor; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Wait; @@ -97,7 +94,8 @@ public abstract class AbstractLauncherUiTest { protected LooperExecutor mMainThreadExecutor = MAIN_EXECUTOR; protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation()); - protected final LauncherInstrumentation mLauncher = new LauncherInstrumentation(); + protected final LauncherInstrumentation mLauncher = + new LauncherInstrumentation(getInstrumentation()); protected Context mTargetContext; protected String mTargetPackage; @@ -109,9 +107,8 @@ public abstract class AbstractLauncherUiTest { } if (TestHelpers.isInLauncherProcess()) { Utilities.enableRunningInTestHarnessForTests(); - mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand( - TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString()). - getString("result")); + mLauncher.setSystemHealthSupplier(() -> TestCommandReceiver.callCommand( + TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE).getString("result")); mLauncher.setOnSettledStateAction( containerType -> executeOnLauncher( launcher -> @@ -176,13 +173,15 @@ public abstract class AbstractLauncherUiTest { mTargetContext = InstrumentationRegistry.getTargetContext(); mTargetPackage = mTargetContext.getPackageName(); + // Unlock the phone + mDevice.executeShellCommand("input keyevent 82"); } @After public void verifyLauncherState() { try { // Limits UI tests affecting tests running after them. - mLauncher.waitForLauncherInitialized(); + waitForModelLoaded(); } catch (Throwable t) { Log.e(TAG, "Couldn't deinit after a test, exiting tests, see logs for failures that " @@ -221,36 +220,14 @@ public abstract class AbstractLauncherUiTest { } catch (Throwable t) { throw new IllegalArgumentException(t); } - mLauncher.waitForLauncherInitialized(); + waitForModelLoaded(); } - /** - * Adds {@param item} on the homescreen on the 0th screen - */ - protected void addItemToScreen(ItemInfo item) { - ContentResolver resolver = mTargetContext.getContentResolver(); - int screenId = FIRST_SCREEN_ID; - // Update the screen id counter for the provider. - LauncherSettings.Settings.call(resolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID); - - if (screenId > FIRST_SCREEN_ID) { - screenId = FIRST_SCREEN_ID; - } - - // Insert the item - ContentWriter writer = new ContentWriter(mTargetContext); - item.id = LauncherSettings.Settings.call( - resolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID) - .getInt(LauncherSettings.Settings.EXTRA_VALUE); - item.screenId = screenId; - item.onAddToDatabase(writer); - writer.put(LauncherSettings.Favorites._ID, item.id); - resolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(mTargetContext)); - resetLoaderState(); - - // Launch the home activity - mDevice.pressHome(); - mLauncher.waitForLauncherInitialized(); + protected void waitForModelLoaded() { + waitForLauncherCondition("Launcher model didn't load", launcher -> { + final LauncherModel model = LauncherAppState.getInstance(mTargetContext).getModel(); + return model.getCallback() == null || model.isModelLoaded(); + }); } /** @@ -335,8 +312,9 @@ public abstract class AbstractLauncherUiTest { } protected LauncherActivityInfo getSettingsApp() { - return mTargetContext.getSystemService(LauncherApps.class) - .getActivityList("com.android.settings", Process.myUserHandle()).get(0); + return LauncherAppsCompat.getInstance(mTargetContext) + .getActivityList("com.android.settings", + Process.myUserHandle()).get(0); } /** diff --git a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java index 1d89d6edcb..a76b4a4886 100644 --- a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java +++ b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java @@ -30,7 +30,7 @@ import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.LauncherAppWidgetProviderInfo; -import com.android.launcher3.testcomponent.TestCommandProvider; +import com.android.launcher3.testcomponent.TestCommandReceiver; import com.android.launcher3.util.LauncherLayoutBuilder; import com.android.launcher3.util.rule.ShellCommandRule; @@ -63,7 +63,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { PackageManager pm = mTargetContext.getPackageManager(); ProviderInfo pi = pm.getProviderInfo(new ComponentName(mContext, - TestCommandProvider.class), 0); + TestCommandReceiver.class), 0); mAuthority = pi.authority; } @@ -73,6 +73,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); + waitForModelLoaded(); mLauncher.getWorkspace().getHotseatAppIcon(getSettingsApp().getLabel().toString()); } @@ -88,6 +89,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); + waitForModelLoaded(); // Verify widget present assertTrue("Widget is not present", @@ -104,6 +106,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest { // Launch the home activity mDevice.pressHome(); + waitForModelLoaded(); mLauncher.getWorkspace().getHotseatFolder("Folder: Copy"); } diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index 709822bbbf..2cf6c2ba7f 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -342,22 +342,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { } } - /** - * Test dragging a custom shortcut to the workspace and launch it. - * - * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it. - * Custom shortcuts are replaced by deep shortcuts after api 25. - */ - @Test - @PortraitLandscape - public void testDragCustomShortcut() { - mLauncher.getWorkspace().openAllWidgets() - .getWidget("com.android.launcher3.testcomponent.CustomShortcutConfigActivity") - .dragToWorkspace(); - mLauncher.getWorkspace().getWorkspaceAppIcon("Shortcut") - .launch(getAppPackageName()); - } - public static String getAppPackageName() { return getInstrumentation().getContext().getPackageName(); } diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java index e1b3edeb5a..3f35a3a73a 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java @@ -41,6 +41,7 @@ import com.android.launcher3.util.Wait; import com.android.launcher3.util.rule.ShellCommandRule; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,8 +53,7 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class AddConfigWidgetTest extends AbstractLauncherUiTest { - @Rule - public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); + @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); private LauncherAppWidgetProviderInfo mWidgetInfo; private AppWidgetManager mAppWidgetManager; @@ -70,12 +70,14 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest { @Test @PortraitLandscape + @org.junit.Ignore public void testWidgetConfig() throws Throwable { runTest(true); } @Test @PortraitLandscape + @org.junit.Ignore public void testConfigCancelled() throws Throwable { runTest(false); } diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java index b8ca5ded38..1edce22ec6 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java @@ -30,6 +30,7 @@ import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TestViewHelpers; import com.android.launcher3.util.rule.ShellCommandRule; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,11 +42,11 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class AddWidgetTest extends AbstractLauncherUiTest { - @Rule - public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); + @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); @Test @PortraitLandscape + @org.junit.Ignore public void testDragIcon() throws Throwable { clearHomescreen(); mDevice.pressHome(); diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index 3d691da092..e6348d9c02 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -15,9 +15,7 @@ */ package com.android.launcher3.ui.widget; -import static androidx.test.InstrumentationRegistry.getTargetContext; - -import static com.android.launcher3.widget.WidgetHostViewLoader.getDefaultOptionsForWidget; +import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -27,7 +25,6 @@ import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.ContentResolver; -import android.content.Context; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; @@ -42,12 +39,15 @@ import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherSettings; import com.android.launcher3.compat.AppWidgetManagerCompat; -import com.android.launcher3.pm.PackageInstallerCompat; +import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.tapl.Workspace; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TestViewHelpers; +import com.android.launcher3.util.ContentWriter; +import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.rule.ShellCommandRule; import com.android.launcher3.widget.PendingAddWidgetInfo; +import com.android.launcher3.widget.WidgetHostViewLoader; import org.junit.After; import org.junit.Before; @@ -57,6 +57,7 @@ import org.junit.runner.RunWith; import java.util.HashSet; import java.util.Set; +import java.util.function.Consumer; /** * Tests for bind widget flow. @@ -71,6 +72,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); private ContentResolver mResolver; + private AppWidgetManagerCompat mWidgetManager; // Objects created during test, which should be cleaned up in the end. private Cursor mCursor; @@ -83,6 +85,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { super.setUp(); mResolver = mTargetContext.getContentResolver(); + mWidgetManager = AppWidgetManagerCompat.getInstance(mTargetContext); // Clear all existing data LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); @@ -105,7 +108,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, true); LauncherAppWidgetInfo item = createWidgetInfo(info, true); - addItemToScreen(item); + setupContents(item); verifyWidgetPresent(info); } @@ -114,7 +117,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false); LauncherAppWidgetInfo item = createWidgetInfo(info, true); - addItemToScreen(item); + setupContents(item); verifyWidgetPresent(info); } @@ -124,7 +127,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetInfo item = createWidgetInfo(info, false); item.appWidgetId = -33; - addItemToScreen(item); + setupContents(item); final Workspace workspace = mLauncher.getWorkspace(); // Item deleted from db @@ -145,7 +148,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetInfo item = createWidgetInfo(info, false); item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID; - addItemToScreen(item); + setupContents(item); verifyWidgetPresent(info); } @@ -158,7 +161,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { LauncherAppWidgetInfo item = createWidgetInfo(info, false); item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID; - addItemToScreen(item); + setupContents(item); verifyPendingWidgetPresent(); // Item deleted from db @@ -180,7 +183,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; - addItemToScreen(item); + setupContents(item); assertTrue("Pending widget exists", mLauncher.getWorkspace().tryGetPendingWidget(0) == null); @@ -199,7 +202,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { | LauncherAppWidgetInfo.FLAG_RESTORE_STARTED | LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; - addItemToScreen(item); + setupContents(item); verifyPendingWidgetPresent(); // Verify item still exists in db @@ -227,7 +230,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller(); mSessionId = installer.createSession(params); - addItemToScreen(item); + setupContents(item); verifyPendingWidgetPresent(); // Verify item still exists in db @@ -242,6 +245,35 @@ public class BindWidgetTest extends AbstractLauncherUiTest { & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID); } + /** + * Adds {@param item} on the homescreen on the 0th screen at 0,0, and verifies that the + * widget class is displayed on the homescreen. + */ + private void setupContents(LauncherAppWidgetInfo item) { + int screenId = FIRST_SCREEN_ID; + // Update the screen id counter for the provider. + LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID); + + if (screenId > FIRST_SCREEN_ID) { + screenId = FIRST_SCREEN_ID; + } + + // Insert the item + ContentWriter writer = new ContentWriter(mTargetContext); + item.id = LauncherSettings.Settings.call( + mResolver, LauncherSettings.Settings.METHOD_NEW_ITEM_ID) + .getInt(LauncherSettings.Settings.EXTRA_VALUE); + item.screenId = screenId; + item.onAddToDatabase(writer); + writer.put(LauncherSettings.Favorites._ID, item.id); + mResolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(mTargetContext)); + resetLoaderState(); + + // Launch the home activity + mDevice.pressHome(); + waitForModelLoaded(); + } + private void verifyWidgetPresent(LauncherAppWidgetProviderInfo info) { assertTrue("Widget is not present", mLauncher.getWorkspace().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null); @@ -257,10 +289,8 @@ public class BindWidgetTest extends AbstractLauncherUiTest { * @param bindWidget if true the info is bound and a valid widgetId is assigned to * the LauncherAppWidgetInfo */ - public static LauncherAppWidgetInfo createWidgetInfo( + private LauncherAppWidgetInfo createWidgetInfo( LauncherAppWidgetProviderInfo info, boolean bindWidget) { - Context targetContext = getTargetContext(); - LauncherAppWidgetInfo item = new LauncherAppWidgetInfo( LauncherAppWidgetInfo.NO_ID, info.provider); item.spanX = info.minSpanX; @@ -278,12 +308,11 @@ public class BindWidgetTest extends AbstractLauncherUiTest { pendingInfo.spanY = item.spanY; pendingInfo.minSpanX = item.minSpanX; pendingInfo.minSpanY = item.minSpanY; - Bundle options = getDefaultOptionsForWidget(targetContext, pendingInfo); + Bundle options = WidgetHostViewLoader.getDefaultOptionsForWidget(mTargetContext, pendingInfo); - AppWidgetHost host = new LauncherAppWidgetHost(targetContext); + AppWidgetHost host = new LauncherAppWidgetHost(mTargetContext); int widgetId = host.allocateAppWidgetId(); - if (!AppWidgetManagerCompat.getInstance(targetContext) - .bindAppWidgetIdIfAllowed(widgetId, info, options)) { + if (!mWidgetManager.bindAppWidgetIdIfAllowed(widgetId, info, options)) { host.deleteAppWidgetId(widgetId); throw new IllegalArgumentException("Unable to bind widget id"); } @@ -302,7 +331,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { Set activePackage = getOnUiThread(() -> { Set packages = new HashSet<>(); - PackageInstallerCompat.getInstance(mTargetContext).getActiveSessions() + PackageInstallerCompat.getInstance(mTargetContext).updateAndGetActiveSessionCache() .keySet().forEach(packageUserKey -> packages.add(packageUserKey.mPackageName)); return packages; }); diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java index d7f41bf041..8391ae713c 100644 --- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java +++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java @@ -37,11 +37,11 @@ public class TestStabilityRule implements TestRule { private static final String TAG = "TestStabilityRule"; private static final Pattern LAUNCHER_BUILD = Pattern.compile("^(" - + "(?(BuildFromAndroidStudio|" - + "([0-9]+|[A-Z])-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+))|" - + "(?([0-9]+|[A-Z])-P[0-9]+)|" - + "(?([0-9]+|[A-Z])-[0-9]+)|" - + "(?[0-9]+|[A-Z])" + + "(?BuildFromAndroidStudio)|" + + "(?[0-9]+-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+)|" + + "(?[0-9]+-P[0-9]+)|" + + "(?[0-9]+-[0-9]+|" + + "(?[0-9]+))" + ")$"); private static final Pattern PLATFORM_BUILD = Pattern.compile("^(" @@ -61,7 +61,71 @@ public class TestStabilityRule implements TestRule { return new Statement() { @Override public void evaluate() throws Throwable { - getRunFlavor(); + final String launcherVersion = + getInstrumentation(). + getContext(). + getPackageManager(). + getPackageInfo( + UiDevice.getInstance(getInstrumentation()). + getLauncherPackageName(), + 0). + versionName; + + final Matcher launcherBuildMatcher = LAUNCHER_BUILD.matcher(launcherVersion); + + boolean launcherLocalBuild = false; + boolean launcherUnbundledPresubmit = false; + boolean launcherUnbundledPostsubmit = false; + boolean launcherPlatform = false; + + if (!launcherBuildMatcher.find()) { + Log.e(TAG, "Match not found"); + } else if (launcherBuildMatcher.group("androidStudio") != null + || launcherBuildMatcher.group("commandLine") != null) { + launcherLocalBuild = true; + } else if (launcherBuildMatcher.group("presubmit") != null) { + launcherUnbundledPresubmit = true; + } else if (launcherBuildMatcher.group("postsubmit") != null) { + launcherUnbundledPostsubmit = true; + } else if (launcherBuildMatcher.group("platform") != null) { + launcherPlatform = true; + } else { + Log.e(TAG, "ERROR1"); + } + + boolean platformLocalBuild = false; + boolean platformPresubmit = false; + boolean platformPostsubmit = false; + + final String platformVersion = Build.VERSION.INCREMENTAL; + final Matcher platformBuildMatcher = PLATFORM_BUILD.matcher(platformVersion); + if (!platformBuildMatcher.find()) { + Log.e(TAG, "Match not found"); + } else if (platformBuildMatcher.group("commandLine") != null) { + platformLocalBuild = true; + } else if (platformBuildMatcher.group("presubmit") != null) { + platformPresubmit = true; + } else if (platformBuildMatcher.group("postsubmit") != null) { + platformPostsubmit = true; + } else { + Log.e(TAG, "ERROR2"); + } + + Log.d(TAG, "Launcher: " + launcherVersion + ", platform: " + platformVersion); + + if (launcherLocalBuild && (platformLocalBuild || platformPostsubmit)) { + Log.d(TAG, "LOCAL RUN"); + } else if (launcherUnbundledPresubmit && platformPostsubmit) { + Log.d(TAG, "UNBUNDLED PRESUBMIT"); + } else if (launcherUnbundledPostsubmit && platformPostsubmit) { + Log.d(TAG, "UNBUNDLED POSTSUBMIT"); + } else if (launcherPlatform && platformPresubmit) { + Log.d(TAG, "PLATFORM PRESUBMIT"); + } else if (launcherPlatform && platformPostsubmit) { + Log.d(TAG, "PLATFORM POSTSUBMIT"); + } else { + Log.e(TAG, "ERROR3"); + } base.evaluate(); } @@ -70,50 +134,4 @@ public class TestStabilityRule implements TestRule { return base; } } - - private static void getRunFlavor() throws Exception { - final String launcherVersion = getInstrumentation(). - getContext(). - getPackageManager(). - getPackageInfo( - UiDevice.getInstance(getInstrumentation()). - getLauncherPackageName(), - 0). - versionName; - - final Matcher launcherBuildMatcher = LAUNCHER_BUILD.matcher(launcherVersion); - - if (!launcherBuildMatcher.find()) { - Log.e(TAG, "Match not found"); - } - - final String platformVersion = Build.VERSION.INCREMENTAL; - final Matcher platformBuildMatcher = PLATFORM_BUILD.matcher(platformVersion); - - if (!platformBuildMatcher.find()) { - Log.e(TAG, "Match not found"); - } - - Log.d(TAG, "Launcher: " + launcherVersion + ", platform: " + platformVersion); - - if (launcherBuildMatcher.group("local") != null && ( - platformBuildMatcher.group("commandLine") != null || - platformBuildMatcher.group("postsubmit") != null)) { - Log.d(TAG, "LOCAL RUN"); - } else if (launcherBuildMatcher.group("presubmit") != null - && platformBuildMatcher.group("postsubmit") != null) { - Log.d(TAG, "UNBUNDLED PRESUBMIT"); - } else if (launcherBuildMatcher.group("postsubmit") != null - && platformBuildMatcher.group("postsubmit") != null) { - Log.d(TAG, "UNBUNDLED POSTSUBMIT"); - } else if (launcherBuildMatcher.group("platform") != null - && platformBuildMatcher.group("presubmit") != null) { - Log.d(TAG, "PLATFORM PRESUBMIT"); - } else if (launcherBuildMatcher.group("platform") != null - && platformBuildMatcher.group("postsubmit") != null) { - Log.d(TAG, "PLATFORM POSTSUBMIT"); - } else { - Log.e(TAG, "ERROR3"); - } - } } diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index e1e9b8d851..f070280ea2 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -53,8 +53,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { return LauncherInstrumentation.ContainerType.ALL_APPS; } - private boolean hasClickableIcon(UiObject2 allAppsContainer, UiObject2 appListRecycler, - BySelector appIconSelector, int displayBottom) { + private boolean hasClickableIcon( + UiObject2 allAppsContainer, UiObject2 appListRecycler, BySelector appIconSelector) { final UiObject2 icon = appListRecycler.findObject(appIconSelector); if (icon == null) { LauncherInstrumentation.log("hasClickableIcon: icon not visible"); @@ -66,10 +66,6 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { LauncherInstrumentation.log("hasClickableIcon: icon center is under search box"); return false; } - if (iconBounds.bottom > displayBottom) { - LauncherInstrumentation.log("hasClickableIcon: icon center bellow bottom offset"); - return false; - } LauncherInstrumentation.log("hasClickableIcon: icon is clickable"); return true; } @@ -94,32 +90,21 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view"); - final UiObject2 searchBox = getSearchBox(allAppsContainer); - - int bottomGestureMargin = ResourceUtils.getNavbarSize( - ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; - int deviceHeight = mLauncher.getDevice().getDisplayHeight(); - int displayBottom = deviceHeight - bottomGestureMargin; allAppsContainer.setGestureMargins( 0, getSearchBox(allAppsContainer).getVisibleBounds().bottom + 1, 0, - bottomGestureMargin); + ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, + mLauncher.getResources()) + 1); final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher); - if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, - displayBottom)) { + if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) { scrollBackToBeginning(); int attempts = 0; - int scroll = getAllAppsScroll(); + int scroll = getScroll(allAppsContainer); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) { - while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, - displayBottom)) { - mLauncher.scrollToLastVisibleRow( - allAppsContainer, - mLauncher.getObjectsInContainer(allAppsContainer, "icon"), - searchBox.getVisibleBounds().bottom - - allAppsContainer.getVisibleBounds().top); - final int newScroll = getAllAppsScroll(); + while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)) { + mLauncher.scroll(allAppsContainer, Direction.DOWN, 0.8f, null, 50); + final int newScroll = getScroll(allAppsContainer); if (newScroll == scroll) break; mLauncher.assertTrue( @@ -132,11 +117,8 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { verifyActiveContainer(); } - // Ignore bottom offset selection here as there might not be any scroll more scroll - // region available. mLauncher.assertTrue("Unable to scroll to a clickable icon: " + appName, - hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector, - deviceHeight)); + hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)); final UiObject2 appIcon = mLauncher.waitForObjectInContainer(appListRecycler, appIconSelector); @@ -154,16 +136,16 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { int attempts = 0; final Rect margins = new Rect(0, searchBox.getVisibleBounds().bottom + 1, 0, 5); - for (int scroll = getAllAppsScroll(); + for (int scroll = getScroll(allAppsContainer); scroll != 0; - scroll = getAllAppsScroll()) { + scroll = getScroll(allAppsContainer)) { mLauncher.assertTrue("Negative scroll position", scroll > 0); mLauncher.assertTrue( "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS, ++attempts <= MAX_SCROLL_ATTEMPTS); - mLauncher.scroll(allAppsContainer, Direction.UP, margins, 50); + mLauncher.scroll(allAppsContainer, Direction.UP, 1, margins, 50); } try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) { @@ -172,10 +154,9 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { } } - private int getAllAppsScroll() { - return mLauncher.getTestInfo( - TestProtocol.REQUEST_APPS_LIST_SCROLL_Y) - .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); + private int getScroll(UiObject2 allAppsContainer) { + return mLauncher.getAnswerFromLauncher(allAppsContainer, TestProtocol.GET_SCROLL_MESSAGE). + getInt(TestProtocol.SCROLL_Y_FIELD, -1); } private UiObject2 getSearchBox(UiObject2 allAppsContainer) { @@ -191,7 +172,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); // Start the gesture in the center to avoid starting at elements near the top. mLauncher.scroll( - allAppsContainer, Direction.DOWN, new Rect(0, 0, 0, mHeight / 2), 10); + allAppsContainer, Direction.DOWN, 1, new Rect(0, 0, 0, mHeight / 2), 10); verifyActiveContainer(); } } @@ -205,7 +186,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { final UiObject2 allAppsContainer = verifyActiveContainer(); // Start the gesture in the center, for symmetry with forward. mLauncher.scroll( - allAppsContainer, Direction.UP, new Rect(0, mHeight / 2, 0, 0), 10); + allAppsContainer, Direction.UP, 1, new Rect(0, mHeight / 2, 0, 0), 10); verifyActiveContainer(); } } diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java index 8b5792cae3..bcce8ef579 100644 --- a/tests/tapl/com/android/launcher3/tapl/Background.java +++ b/tests/tapl/com/android/launcher3/tapl/Background.java @@ -23,7 +23,6 @@ import android.os.SystemClock; import android.view.MotionEvent; import androidx.annotation.NonNull; -import androidx.test.uiautomator.UiObject2; import com.android.launcher3.testing.TestProtocol; @@ -105,12 +104,7 @@ public class Background extends LauncherInstrumentation.VisibleContainer { startY = endY = mLauncher.getDevice().getDisplayHeight() / 2; } - if (mLauncher.isFallbackOverview()) { - mLauncher.linearGesture(startX, startY, endX, endY, 10); - new BaseOverview(mLauncher); - } else { - mLauncher.swipeToState(startX, startY, endX, endY, 10, expectedState); - } + mLauncher.swipeToState(startX, startY, endX, endY, 10, expectedState); break; } @@ -120,46 +114,6 @@ public class Background extends LauncherInstrumentation.VisibleContainer { } } - /** - * Swipes right or double presses the square button to switch to the previous app. - */ - public Background quickSwitchToPreviousApp() { - try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( - "want to quick switch to the previous app")) { - verifyActiveContainer(); - quickSwitchToPreviousApp(getExpectedStateForQuickSwitch()); - return new Background(mLauncher); - } - } - - protected int getExpectedStateForQuickSwitch() { - return BACKGROUND_APP_STATE_ORDINAL; - } - - protected void quickSwitchToPreviousApp(int expectedState) { - switch (mLauncher.getNavigationModel()) { - case ZERO_BUTTON: - // Fall through, zero button and two button modes behave the same. - case TWO_BUTTON: { - // Swipe from the bottom left to the bottom right of the screen. - final int startX = 0; - final int startY = getSwipeStartY(); - final int endX = mLauncher.getDevice().getDisplayWidth(); - final int endY = startY; - mLauncher.swipeToState(startX, startY, endX, endY, 20, expectedState); - break; - } - - case THREE_BUTTON: - // Double press the recents button. - UiObject2 recentsButton = mLauncher.waitForSystemUiObject("recent_apps"); - recentsButton.click(); - mLauncher.getOverview(); - recentsButton.click(); - break; - } - } - protected String getSwipeHeightRequestName() { return TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT; } diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index 8ccfc05bf7..eaa21aeebf 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -55,7 +55,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { final int leftMargin = mLauncher.getTestInfo( TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN). getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); - mLauncher.scroll(overview, Direction.LEFT, new Rect(leftMargin + 1, 0, 0, 0), 20); + mLauncher.scroll(overview, Direction.LEFT, 1, new Rect(leftMargin, 0, 0, 0), 20); verifyActiveContainer(); } } @@ -89,7 +89,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { final int rightMargin = mLauncher.getTestInfo( TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN). getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); - mLauncher.scroll(overview, Direction.RIGHT, new Rect(0, 0, rightMargin + 1, 0), 20); + mLauncher.scroll(overview, Direction.RIGHT, 1, new Rect(0, 0, rightMargin, 0), 20); verifyActiveContainer(); } } diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java index e0fe933ee9..cfc43749d1 100644 --- a/tests/tapl/com/android/launcher3/tapl/Home.java +++ b/tests/tapl/com/android/launcher3/tapl/Home.java @@ -17,7 +17,6 @@ package com.android.launcher3.tapl; import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL; -import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL; import androidx.annotation.NonNull; @@ -59,9 +58,4 @@ public abstract class Home extends Background { } } } - - @Override - protected int getExpectedStateForQuickSwitch() { - return QUICK_SWITCH_STATE_ORDINAL; - } } \ No newline at end of file diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 484cbb61c3..383c3cef31 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -37,6 +37,7 @@ import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.os.SystemClock; @@ -51,7 +52,6 @@ import android.view.accessibility.AccessibilityEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.By; import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.Configurator; @@ -60,24 +60,20 @@ import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.UiObject2; import androidx.test.uiautomator.Until; -import com.android.launcher3.ResourceUtils; import com.android.launcher3.testing.TestProtocol; import com.android.systemui.shared.system.QuickStepContract; -import java.util.ArrayList; +import org.junit.Assert; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; -import java.util.Collection; -import java.util.Collections; import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import java.util.function.Function; - -import org.junit.Assert; +import java.util.function.Supplier; /** * The main tapl object. The only object that can be explicitly constructed by the using code. It @@ -88,7 +84,6 @@ public final class LauncherInstrumentation { private static final String TAG = "Tapl"; private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20; private static final int GESTURE_STEP_MS = 16; - private static long START_TIME = System.currentTimeMillis(); // Types for launcher containers that the user is interacting with. "Background" is a // pseudo-container corresponding to inactive launcher covered by another app. @@ -139,22 +134,13 @@ public final class LauncherInstrumentation { private int mExpectedRotation = Surface.ROTATION_0; private final Uri mTestProviderUri; private final Deque mDiagnosticContext = new LinkedList<>(); - private Function mSystemHealthSupplier; + private Supplier mSystemHealthSupplier; private Consumer mOnSettledStateAction; /** * Constructs the root of TAPL hierarchy. You get all other objects from it. */ - public LauncherInstrumentation() { - this(InstrumentationRegistry.getInstrumentation()); - } - - /** - * Constructs the root of TAPL hierarchy. You get all other objects from it. - * Deprecated: use the constructor without parameters instead. - */ - @Deprecated public LauncherInstrumentation(Instrumentation instrumentation) { mInstrumentation = instrumentation; mDevice = UiDevice.getInstance(instrumentation); @@ -252,6 +238,10 @@ public final class LauncherInstrumentation { return null; } + public static boolean isAvd() { + return Build.MODEL.contains("Cuttlefish"); + } + static void log(String message) { Log.d(TAG, message); } @@ -306,7 +296,7 @@ public final class LauncherInstrumentation { return "Background"; } - public void setSystemHealthSupplier(Function supplier) { + public void setSystemHealthSupplier(Supplier supplier) { this.mSystemHealthSupplier = supplier; } @@ -326,8 +316,8 @@ public final class LauncherInstrumentation { } return mSystemHealthSupplier != null - ? mSystemHealthSupplier.apply(START_TIME) - : TestHelpers.getSystemHealthMessage(getContext(), START_TIME); + ? mSystemHealthSupplier.get() + : TestHelpers.getSystemHealthMessage(getContext()); } private void fail(String message) { @@ -496,7 +486,7 @@ public final class LauncherInstrumentation { } } - public void waitForLauncherInitialized() { + private void waitForLauncherInitialized() { for (int i = 0; i < 100; ++i) { if (getTestInfo( TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED). @@ -522,6 +512,15 @@ public final class LauncherInstrumentation { } } + Bundle getAnswerFromLauncher(UiObject2 view, String requestTag) { + // Send a fake set-text request to Launcher to initiate a response with requested data. + final String responseTag = requestTag + TestProtocol.RESPONSE_MESSAGE_POSTFIX; + return (Bundle) executeAndWaitForEvent( + () -> view.setText(requestTag), + event -> responseTag.equals(event.getClassName()), + "Launcher didn't respond to request: " + requestTag); + } + /** * Presses nav bar home button. * @@ -535,9 +534,6 @@ public final class LauncherInstrumentation { // accessibility events prior to pressing Home. final String action; if (getNavigationModel() == NavigationModel.ZERO_BUTTON) { - final String anomaly = getAnomalyMessage(); - if (anomaly != null) fail("Can't swipe up to Home: " + anomaly); - final Point displaySize = getRealDisplaySize(); if (hasLauncherObject("deep_shortcuts_container")) { @@ -545,17 +541,13 @@ public final class LauncherInstrumentation { displaySize.x / 2, displaySize.y - 1, displaySize.x / 2, 0, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME); - try (LauncherInstrumentation.Closable c = addContextLayer( - "Swiped up from context menu to home")) { - waitUntilGone("deep_shortcuts_container"); - } + assertTrue("Context menu is still visible afterswiping up to home", + !hasLauncherObject("deep_shortcuts_container")); } if (hasLauncherObject(WORKSPACE_RES_ID)) { log(action = "already at home"); } else { - log("Hierarchy before swiping up to home"); - dumpViewHierarchy(); - log(action = "swiping up to home from " + getVisibleStateMessage()); + log(action = "swiping up to home"); final int finalState = mDevice.hasObject(By.pkg(getLauncherPackageName())) ? NORMAL_STATE_ORDINAL : BACKGROUND_APP_STATE_ORDINAL; @@ -777,36 +769,7 @@ public final class LauncherInstrumentation { TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD))); } - int getBottomGestureSize() { - return ResourceUtils.getNavbarSize( - ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources()) + 1; - } - - int getBottomGestureMargin(UiObject2 container) { - return container.getVisibleBounds().bottom - getRealDisplaySize().y - + getBottomGestureSize(); - } - - void scrollToLastVisibleRow(UiObject2 container, Collection items, int topPadding) { - final UiObject2 lowestItem = Collections.max(items, (i1, i2) -> - Integer.compare(i1.getVisibleBounds().top, i2.getVisibleBounds().top)); - - final int gestureStart = lowestItem.getVisibleBounds().top + getTouchSlop(); - final int distance = gestureStart - container.getVisibleBounds().top - topPadding; - final int bottomMargin = container.getVisibleBounds().height() - distance; - - scroll( - container, - Direction.DOWN, - new Rect( - 0, - 0, - 0, - Math.max(bottomMargin, getBottomGestureMargin(container))), - 150); - } - - void scroll(UiObject2 container, Direction direction, Rect margins, int steps) { + void scroll(UiObject2 container, Direction direction, float percent, Rect margins, int steps) { final Rect rect = container.getVisibleBounds(); if (margins != null) { rect.left += margins.left; @@ -823,26 +786,34 @@ public final class LauncherInstrumentation { switch (direction) { case UP: { startX = endX = rect.centerX(); - startY = rect.top; - endY = rect.bottom - 1; + final int vertCenter = rect.centerY(); + final float halfGestureHeight = rect.height() * percent / 2.0f; + startY = (int) (vertCenter - halfGestureHeight) + 1; + endY = (int) (vertCenter + halfGestureHeight); } break; case DOWN: { startX = endX = rect.centerX(); - startY = rect.bottom - 1; - endY = rect.top; + final int vertCenter = rect.centerY(); + final float halfGestureHeight = rect.height() * percent / 2.0f; + startY = (int) (vertCenter + halfGestureHeight) - 1; + endY = (int) (vertCenter - halfGestureHeight); } break; case LEFT: { startY = endY = rect.centerY(); - startX = rect.left; - endX = rect.right - 1; + final int horizCenter = rect.centerX(); + final float halfGestureWidth = rect.width() * percent / 2.0f; + startX = (int) (horizCenter - halfGestureWidth) + 1; + endX = (int) (horizCenter + halfGestureWidth); } break; case RIGHT: { startY = endY = rect.centerY(); - startX = rect.right - 1; - endX = rect.left; + final int horizCenter = rect.centerX(); + final float halfGestureWidth = rect.width() * percent / 2.0f; + startX = (int) (horizCenter + halfGestureWidth) - 1; + endX = (int) (horizCenter - halfGestureWidth); } break; default: @@ -873,6 +844,10 @@ public final class LauncherInstrumentation { mDevice.waitForIdle(); } + float getDisplayDensity() { + return mInstrumentation.getTargetContext().getResources().getDisplayMetrics().density; + } + int getTouchSlop() { return ViewConfiguration.get(getContext()).getScaledTouchSlop(); } @@ -994,18 +969,4 @@ public final class LauncherInstrumentation { public void produceNativeLeak() { getTestInfo(TestProtocol.REQUEST_NATIVE_LEAK); } - - public void produceViewLeak() { - getTestInfo(TestProtocol.REQUEST_VIEW_LEAK); - } - - public ArrayList getRecentTasks() { - ArrayList tasks = new ArrayList<>(); - ArrayList components = getTestInfo(TestProtocol.REQUEST_RECENT_TASKS_LIST) - .getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD); - for (String s : components) { - tasks.add(ComponentName.unflattenFromString(s)); - } - return tasks; - } } \ No newline at end of file diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java index e88217180d..a089a527ef 100644 --- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java +++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java @@ -77,18 +77,13 @@ public class TestHelpers { return launchers.get(0).activityInfo; } - public static ComponentName getOverviewComponentName() { + public static String getOverviewPackageName() { Resources res = Resources.getSystem(); int id = res.getIdentifier("config_recentsComponentName", "string", "android"); if (id != 0) { - return ComponentName.unflattenFromString(res.getString(id)); + return ComponentName.unflattenFromString(res.getString(id)).getPackageName(); } - return new ComponentName("com.android.systemui", - "com.android.systemui.recents.RecentsActivity"); - } - - public static String getOverviewPackageName() { - return getOverviewComponentName().getPackageName(); + return "com.android.systemui"; } private static String truncateCrash(String text, int maxLines) { @@ -106,11 +101,11 @@ public class TestHelpers { return ret.toString(); } - private static String checkCrash(Context context, String label, long startTime) { + private static String checkCrash(Context context, String label) { DropBoxManager dropbox = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE); Assert.assertNotNull("Unable access the DropBoxManager service", dropbox); - long timestamp = startTime; + long timestamp = System.currentTimeMillis() - 5 * 60000; DropBoxManager.Entry entry; StringBuilder errorDetails = new StringBuilder(); while (null != (entry = dropbox.getNextEntry(label, timestamp))) { @@ -128,7 +123,7 @@ public class TestHelpers { return errorDetails.length() != 0 ? errorDetails.toString() : null; } - public static String getSystemHealthMessage(Context context, long startTime) { + public static String getSystemHealthMessage(Context context) { try { StringBuilder errors = new StringBuilder(); @@ -136,6 +131,7 @@ public class TestHelpers { "system_app_anr", "system_app_crash", "system_app_native_crash", + "system_app_wtf", "system_server_anr", "system_server_crash", "system_server_native_crash", @@ -143,7 +139,7 @@ public class TestHelpers { }; for (String label : labels) { - final String crash = checkCrash(context, label, startTime); + final String crash = checkCrash(context, label); if (crash != null) errors.append(crash); } diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 5fcaa557df..7d308afb99 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -16,6 +16,8 @@ package com.android.launcher3.tapl; +import static org.junit.Assert.fail; + import android.graphics.Point; import android.graphics.Rect; @@ -24,12 +26,13 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.Direction; import androidx.test.uiautomator.UiObject2; -import java.util.Collection; +import com.android.launcher3.ResourceUtils; /** * All widgets container. */ public final class Widgets extends LauncherInstrumentation.VisibleContainer { + private static final Rect MARGINS = new Rect(100, 100, 100, 100); private static final int FLING_STEPS = 10; Widgets(LauncherInstrumentation launcher) { @@ -45,11 +48,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling forward in widgets")) { LauncherInstrumentation.log("Widgets.flingForward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - mLauncher.scroll( - widgetsContainer, - Direction.DOWN, - new Rect(0, 0, 0, mLauncher.getBottomGestureMargin(widgetsContainer) + 1), - FLING_STEPS); + mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { verifyActiveContainer(); } @@ -65,11 +64,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling backwards in widgets")) { LauncherInstrumentation.log("Widgets.flingBackward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - mLauncher.scroll( - widgetsContainer, - Direction.UP, - new Rect(0, 0, widgetsContainer.getVisibleBounds().width(), 0), - FLING_STEPS); + mLauncher.scroll(widgetsContainer, Direction.UP, 1f, MARGINS, FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) { verifyActiveContainer(); } @@ -83,33 +78,32 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { } public Widget getWidget(String labelText) { + final int margin = ResourceUtils.getNavbarSize( + ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; final UiObject2 widgetsContainer = verifyActiveContainer(); + widgetsContainer.setGestureMargins(0, 0, 0, margin); + final Point displaySize = mLauncher.getRealDisplaySize(); - final BySelector labelSelector = By.clazz("android.widget.TextView").text(labelText); int i = 0; - for (; ; ) { - final Collection cells = mLauncher.getObjectsInContainer( - widgetsContainer, "widgets_cell_list_container"); - mLauncher.assertTrue("Widgets doesn't have 2 rows", cells.size() >= 2); - for (UiObject2 cell : cells) { - final UiObject2 label = cell.findObject(labelSelector); - if (label == null) continue; + final BySelector selector = By.clazz("android.widget.TextView").text(labelText); + for (; ; ) { + final UiObject2 label = mLauncher.tryWaitForLauncherObject(selector, 300); + if (label != null) { final UiObject2 widget = label.getParent().getParent(); mLauncher.assertEquals( "View is not WidgetCell", "com.android.launcher3.widget.WidgetCell", widget.getClassName()); - if (widget.getVisibleBounds().bottom - <= displaySize.y - mLauncher.getBottomGestureSize()) { + if (widget.getVisibleBounds().bottom <= displaySize.y - margin) { return new Widget(mLauncher, widget); } } - mLauncher.assertTrue("Too many attempts", ++i <= 40); - mLauncher.scrollToLastVisibleRow(widgetsContainer, cells, 0); + if (++i > 40) fail("Too many attempts"); + mLauncher.scroll(widgetsContainer, Direction.DOWN, 0.7f, MARGINS, 50); } } } diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index d1261e07be..510ea14091 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -38,6 +38,8 @@ import com.android.launcher3.testing.TestProtocol; * Operations on the workspace screen. */ public final class Workspace extends Home { + private static final float FLING_SPEED = + LauncherInstrumentation.isAvd() ? 1500.0F : 3500.0F; private static final int DRAG_DURACTION = 2000; private static final int FLING_STEPS = 10; private final UiObject2 mHotseat; @@ -140,7 +142,7 @@ public final class Workspace extends Home { } private boolean isWorkspaceScrollable(UiObject2 workspace) { - return workspace.getChildCount() > 1; + return workspace.isScrollable(); } @NonNull @@ -180,8 +182,8 @@ public final class Workspace extends Home { */ public void flingForward() { final UiObject2 workspace = verifyActiveContainer(); - mLauncher.scroll(workspace, Direction.RIGHT, - new Rect(0, 0, mLauncher.getEdgeSensitivityWidth() + 1, 0), + mLauncher.scroll(workspace, Direction.RIGHT, 1f, + new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0), FLING_STEPS); verifyActiveContainer(); } @@ -192,8 +194,8 @@ public final class Workspace extends Home { */ public void flingBackward() { final UiObject2 workspace = verifyActiveContainer(); - mLauncher.scroll(workspace, Direction.LEFT, - new Rect(mLauncher.getEdgeSensitivityWidth() + 1, 0, 0, 0), + mLauncher.scroll(workspace, Direction.LEFT, 1f, + new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0), FLING_STEPS); verifyActiveContainer(); }