[Memory Leak] Fix leak of TouchInteractionService from DisplayInfoChangeListener

Fix: 394672098
Flag: NONE - released code
Test: manual
Change-Id: I99bfd783e8be34066e29072f5c1a6719802bde05
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index e1e962a..090ccdc 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -114,7 +114,6 @@
 
     private final RotationTouchHelper mRotationTouchHelper;
     private final TaskStackChangeListener mPipListener;
-    private final DaggerSingletonTracker mLifeCycle;
     // Cache for better performance since it doesn't change at runtime.
     private final boolean mCanImeRenderGesturalNavButtons =
             InputMethodService.canImeRenderGesturalNavButtons();
@@ -152,16 +151,15 @@
         mExclusionManager = exclusionManager;
         mContextualSearchStateManager = contextualSearchStateManager;
         mRotationTouchHelper = rotationTouchHelper;
-        mLifeCycle = lifeCycle;
         mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
 
         // Register for exclusion updates
-        mLifeCycle.addCloseable(this::unregisterExclusionListener);
+        lifeCycle.addCloseable(this::unregisterExclusionListener);
 
         // Register for display changes changes
         mDisplayController.addChangeListener(this);
         onDisplayInfoChanged(context, mDisplayController.getInfo(), CHANGE_ALL);
-        mLifeCycle.addCloseable(() -> mDisplayController.removeChangeListener(this));
+        lifeCycle.addCloseable(() -> mDisplayController.removeChangeListener(this));
 
         if (mIsOneHandedModeSupported) {
             Uri oneHandedUri = Settings.Secure.getUriFor(ONE_HANDED_ENABLED);
@@ -169,7 +167,7 @@
                     enabled -> mIsOneHandedModeEnabled = enabled;
             settingsCache.register(oneHandedUri, onChangeListener);
             mIsOneHandedModeEnabled = settingsCache.getValue(oneHandedUri);
-            mLifeCycle.addCloseable(() -> settingsCache.unregister(oneHandedUri, onChangeListener));
+            lifeCycle.addCloseable(() -> settingsCache.unregister(oneHandedUri, onChangeListener));
         } else {
             mIsOneHandedModeEnabled = false;
         }
@@ -180,7 +178,7 @@
                 enabled -> mIsSwipeToNotificationEnabled = enabled;
         settingsCache.register(swipeBottomNotificationUri, onChangeListener);
         mIsSwipeToNotificationEnabled = settingsCache.getValue(swipeBottomNotificationUri);
-        mLifeCycle.addCloseable(
+        lifeCycle.addCloseable(
                 () -> settingsCache.unregister(swipeBottomNotificationUri, onChangeListener));
 
         Uri setupCompleteUri = Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE);
@@ -188,7 +186,7 @@
         if (!mIsUserSetupComplete) {
             SettingsCache.OnChangeListener userSetupChangeListener = e -> mIsUserSetupComplete = e;
             settingsCache.register(setupCompleteUri, userSetupChangeListener);
-            mLifeCycle.addCloseable(
+            lifeCycle.addCloseable(
                     () -> settingsCache.unregister(setupCompleteUri, userSetupChangeListener));
         }
 
@@ -210,15 +208,19 @@
             }
         };
         TaskStackChangeListeners.getInstance().registerTaskStackListener(mPipListener);
-        mLifeCycle.addCloseable(() ->
+        lifeCycle.addCloseable(() ->
                 TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mPipListener));
     }
 
     /**
      * Adds a listener for the nav mode change, guaranteed to be called after the device state's
      * mode has changed.
+     *
+     * @return Added {@link DisplayInfoChangeListener} so that caller is
+     * responsible for removing the listener from {@link DisplayController} to avoid memory leak.
      */
-    public void addNavigationModeChangedCallback(Runnable callback) {
+    public DisplayController.DisplayInfoChangeListener addNavigationModeChangedCallback(
+            Runnable callback) {
         DisplayController.DisplayInfoChangeListener listener = (context, info, flags) -> {
             if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
                 callback.run();
@@ -226,7 +228,16 @@
         };
         mDisplayController.addChangeListener(listener);
         callback.run();
-        mLifeCycle.addCloseable(() -> mDisplayController.removeChangeListener(listener));
+        return listener;
+    }
+
+    /**
+     * Remove the {DisplayController.DisplayInfoChangeListener} added from
+     * {@link #addNavigationModeChangedCallback} when {@link TouchInteractionService} is destroyed.
+     */
+    public void removeDisplayInfoChangeListener(
+            DisplayController.DisplayInfoChangeListener listener) {
+        mDisplayController.removeChangeListener(listener);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 51e59ff..d77516e 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -576,6 +576,8 @@
 
     private DesktopAppLaunchTransitionManager mDesktopAppLaunchTransitionManager;
 
+    private DisplayController.DisplayInfoChangeListener mDisplayInfoChangeListener;
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -605,7 +607,8 @@
 
         // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
         LockedUserState.get(this).runOnUserUnlocked(mUserUnlockedRunnable);
-        mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
+        mDisplayInfoChangeListener =
+                mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
         ScreenOnTracker.INSTANCE.get(this).addListener(mScreenOnListener);
     }
 
@@ -757,7 +760,7 @@
             mDesktopAppLaunchTransitionManager.unregisterTransitions();
         }
         mDesktopAppLaunchTransitionManager = null;
-
+        mDeviceState.removeDisplayInfoChangeListener(mDisplayInfoChangeListener);
         LockedUserState.get(this).removeOnUserUnlockedRunnable(mUserUnlockedRunnable);
         ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener);
         super.onDestroy();