Trigger doze detection using WakefulnessLifecycle

Previously, doze detection used StatusBarStateController, which only
provides a signal at the end of the doze transition. This resulted in
the handles only animating away once the screen was already off. Using
the WakefulnessLifecycle allows for a callback when the transition
begins instead.

Test: Tested locally
BUG:137742178
Change-Id: I289ef5b5081fa96b1c8e82c4373c7654e8df80cb
Merged-In: I289ef5b5081fa96b1c8e82c4373c7654e8df80cb
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/SystemUIModule.java
index edd2463..defa574 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIModule.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 
+import com.android.systemui.assist.AssistModule;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.util.AsyncSensorManager;
@@ -33,7 +34,7 @@
  * A dagger module for injecting components of System UI that are not overridden by the System UI
  * implementation.
  */
-@Module
+@Module(includes = {AssistModule.class})
 public abstract class SystemUIModule {
 
     @Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
index 25d1645..738ec80 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.assist;
 
+import static com.android.systemui.assist.AssistModule.ASSIST_HANDLE_THREAD_NAME;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Handler;
@@ -28,20 +30,21 @@
 import com.android.internal.app.AssistUtils;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
 import com.android.systemui.ScreenDecorations;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.phone.NavigationModeController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.EnumMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
 
 /**
  * A class for managing Assistant handle logic.
@@ -49,6 +52,7 @@
  * Controls when visual handles for Assistant gesture affordance should be shown or hidden using an
  * {@link AssistHandleBehavior}.
  */
+@Singleton
 public final class AssistHandleBehaviorController implements AssistHandleCallbacks, Dumpable {
 
     private static final String TAG = "AssistHandleBehavior";
@@ -67,10 +71,9 @@
     private final Handler mHandler;
     private final Runnable mHideHandles = this::hideHandles;
     private final Runnable mShowAndGo = this::showAndGoInternal;
-    private final Supplier<ScreenDecorations> mScreenDecorationsSupplier;
+    private final Provider<ScreenDecorations> mScreenDecorations;
     private final PhenotypeHelper mPhenotypeHelper;
-    private final Map<AssistHandleBehavior, BehaviorController> mBehaviorMap =
-            new EnumMap<>(AssistHandleBehavior.class);
+    private final Map<AssistHandleBehavior, BehaviorController> mBehaviorMap;
 
     private boolean mHandlesShowing = false;
     private long mHandlesLastHiddenAt;
@@ -82,41 +85,25 @@
     private AssistHandleBehavior mCurrentBehavior = AssistHandleBehavior.OFF;
     private boolean mInGesturalMode;
 
-    AssistHandleBehaviorController(Context context, AssistUtils assistUtils, Handler handler) {
-        this(
-                context,
-                assistUtils,
-                handler,
-                () -> SysUiServiceProvider.getComponent(context, ScreenDecorations.class),
-                new PhenotypeHelper(),
-                /* testBehavior = */ null);
-    }
-
-    @VisibleForTesting
+    @Inject
     AssistHandleBehaviorController(
             Context context,
             AssistUtils assistUtils,
-            Handler handler,
-            Supplier<ScreenDecorations> screenDecorationsSupplier,
+            @Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
+            Provider<ScreenDecorations> screenDecorations,
             PhenotypeHelper phenotypeHelper,
-            @Nullable BehaviorController testBehavior) {
+            Map<AssistHandleBehavior, BehaviorController> behaviorMap,
+            NavigationModeController navigationModeController,
+            DumpController dumpController) {
         mContext = context;
         mAssistUtils = assistUtils;
         mHandler = handler;
-        mScreenDecorationsSupplier = screenDecorationsSupplier;
+        mScreenDecorations = screenDecorations;
         mPhenotypeHelper = phenotypeHelper;
-        mBehaviorMap.put(AssistHandleBehavior.OFF, new AssistHandleOffBehavior());
-        mBehaviorMap.put(AssistHandleBehavior.LIKE_HOME, new AssistHandleLikeHomeBehavior());
-        mBehaviorMap.put(
-                AssistHandleBehavior.REMINDER_EXP,
-                new AssistHandleReminderExpBehavior(handler, phenotypeHelper));
-        if (testBehavior != null) {
-            mBehaviorMap.put(AssistHandleBehavior.TEST, testBehavior);
-        }
+        mBehaviorMap = behaviorMap;
 
         mInGesturalMode = QuickStepContract.isGesturalMode(
-                Dependency.get(NavigationModeController.class)
-                        .addListener(this::handleNavigationModeChange));
+                navigationModeController.addListener(this::handleNavigationModeChange));
 
         setBehavior(getBehaviorMode());
         mPhenotypeHelper.addOnPropertiesChangedListener(
@@ -128,7 +115,8 @@
                                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE, null));
                     }
                 });
-        Dependency.get(DumpController.class).addListener(this);
+
+        dumpController.addListener(this);
     }
 
     @Override // AssistHandleCallbacks
@@ -241,7 +229,7 @@
         }
 
         if (handlesUnblocked(ignoreThreshold)) {
-            ScreenDecorations screenDecorations = mScreenDecorationsSupplier.get();
+            ScreenDecorations screenDecorations = mScreenDecorations.get();
             if (screenDecorations == null) {
                 Log.w(TAG, "Couldn't show handles, ScreenDecorations unavailable");
             } else {
@@ -256,7 +244,7 @@
             return;
         }
 
-        ScreenDecorations screenDecorations = mScreenDecorationsSupplier.get();
+        ScreenDecorations screenDecorations = mScreenDecorations.get();
         if (screenDecorations == null) {
             Log.w(TAG, "Couldn't hide handles, ScreenDecorations unavailable");
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java
index 6cf2034..fa6ffe1 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleLikeHomeBehavior.java
@@ -20,25 +20,45 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.shared.system.QuickStepContract;
 
 import java.io.PrintWriter;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
 /**
  * Assistant Handle behavior that makes Assistant handles show/hide when the home handle is
  * shown/hidden, respectively.
  */
+@Singleton
 final class AssistHandleLikeHomeBehavior implements BehaviorController {
 
-    private final StatusBarStateController.StateListener mStatusBarStateListener =
-            new StatusBarStateController.StateListener() {
+    private final WakefulnessLifecycle.Observer mWakefulnessLifecycleObserver =
+            new WakefulnessLifecycle.Observer() {
                 @Override
-                public void onDozingChanged(boolean isDozing) {
-                    handleDozingChanged(isDozing);
+                public void onStartedWakingUp() {
+                    handleDozingChanged(/* isDozing = */ true);
+                }
+
+                @Override
+                public void onFinishedWakingUp() {
+                    handleDozingChanged(/* isDozing = */ false);
+                }
+
+                @Override
+                public void onStartedGoingToSleep() {
+                    handleDozingChanged(/* isDozing = */ true);
+                }
+
+                @Override
+                public void onFinishedGoingToSleep() {
+                    handleDozingChanged(/* isDozing = */ true);
                 }
             };
     private final OverviewProxyService.OverviewProxyListener mOverviewProxyListener =
@@ -48,32 +68,39 @@
             handleSystemUiStateChange(sysuiStateFlags);
         }
     };
-    private final StatusBarStateController mStatusBarStateController;
-    private final OverviewProxyService mOverviewProxyService;
+
+
+    private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
+    private final Lazy<OverviewProxyService> mOverviewProxyService;
 
     private boolean mIsDozing;
     private boolean mIsHomeHandleHiding;
 
     @Nullable private AssistHandleCallbacks mAssistHandleCallbacks;
 
-    AssistHandleLikeHomeBehavior() {
-        mStatusBarStateController = Dependency.get(StatusBarStateController.class);
-        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+    @Inject
+    AssistHandleLikeHomeBehavior(
+            Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
+            Lazy<OverviewProxyService> overviewProxyService) {
+        mWakefulnessLifecycle = wakefulnessLifecycle;
+        mOverviewProxyService = overviewProxyService;
     }
 
     @Override
     public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
         mAssistHandleCallbacks = callbacks;
-        mIsDozing = mStatusBarStateController.isDozing();
-        mStatusBarStateController.addCallback(mStatusBarStateListener);
-        mOverviewProxyService.addCallback(mOverviewProxyListener);
+        mIsDozing = mWakefulnessLifecycle.get().getWakefulness()
+                != WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+        mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver);
+        mOverviewProxyService.get().addCallback(mOverviewProxyListener);
         callbackForCurrentState();
     }
 
     @Override
     public void onModeDeactivated() {
         mAssistHandleCallbacks = null;
-        mOverviewProxyService.removeCallback(mOverviewProxyListener);
+        mWakefulnessLifecycle.get().removeObserver(mWakefulnessLifecycleObserver);
+        mOverviewProxyService.get().removeCallback(mOverviewProxyListener);
     }
 
     private static boolean isHomeHandleHiding(int sysuiStateFlags) {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleOffBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleOffBehavior.java
index f4130ae..df913f9 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleOffBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleOffBehavior.java
@@ -20,9 +20,17 @@
 
 import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /** Assistant handle behavior that hides the Assistant handles. */
+@Singleton
 final class AssistHandleOffBehavior implements BehaviorController {
 
+    @Inject
+    AssistHandleOffBehavior() {
+    }
+
     @Override
     public void onModeActivated(Context context, AssistHandleCallbacks callbacks) {
         callbacks.hide();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index bdc666d..a567315 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.assist;
 
+import static com.android.systemui.assist.AssistModule.ASSIST_HANDLE_THREAD_NAME;
+import static com.android.systemui.assist.AssistModule.UPTIME_NAME;
+
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -24,14 +27,14 @@
 import android.content.IntentFilter;
 import android.content.pm.ResolveInfo;
 import android.os.Handler;
-import android.os.SystemClock;
 import android.provider.Settings;
 
 import androidx.annotation.Nullable;
+import androidx.slice.Clock;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.systemui.Dependency;
 import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -46,11 +49,18 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
 /**
  * Assistant handle behavior that hides the handles when the phone is dozing or in immersive mode,
  * shows the handles when on lockscreen, and shows the handles temporarily when changing tasks or
  * entering overview.
  */
+@Singleton
 final class AssistHandleReminderExpBehavior implements BehaviorController {
 
     private static final String LEARNING_TIME_ELAPSED_KEY = "reminder_exp_learning_time_elapsed";
@@ -83,11 +93,6 @@
                 public void onStateChanged(int newState) {
                     handleStatusBarStateChanged(newState);
                 }
-
-                @Override
-                public void onDozingChanged(boolean isDozing) {
-                    handleDozingChanged(isDozing);
-                }
             };
     private final TaskStackChangeListener mTaskStackChangeListener =
             new TaskStackChangeListener() {
@@ -113,6 +118,18 @@
                     handleSystemUiStateChanged(sysuiStateFlags);
                 }
             };
+    private final WakefulnessLifecycle.Observer mWakefulnessLifecycleObserver =
+            new WakefulnessLifecycle.Observer() {
+                @Override
+                public void onFinishedWakingUp() {
+                    handleDozingChanged(false);
+                }
+
+                @Override
+                public void onStartedGoingToSleep() {
+                    handleDozingChanged(true);
+                }
+    };
     private final BroadcastReceiver mDefaultHomeBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -122,11 +139,14 @@
     private final IntentFilter mDefaultHomeIntentFilter;
     private final Runnable mResetConsecutiveTaskSwitches = this::resetConsecutiveTaskSwitches;
 
+    private final Clock mClock;
     private final Handler mHandler;
     private final PhenotypeHelper mPhenotypeHelper;
-    private final StatusBarStateController mStatusBarStateController;
-    private final ActivityManagerWrapper mActivityManagerWrapper;
-    private final OverviewProxyService mOverviewProxyService;
+    private final Lazy<StatusBarStateController> mStatusBarStateController;
+    private final Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
+    private final Lazy<OverviewProxyService> mOverviewProxyService;
+    private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
+    private final Lazy<PackageManagerWrapper> mPackageManagerWrapper;
 
     private boolean mOnLockscreen;
     private boolean mIsDozing;
@@ -148,12 +168,24 @@
     @Nullable private AssistHandleCallbacks mAssistHandleCallbacks;
     @Nullable private ComponentName mDefaultHome;
 
-    AssistHandleReminderExpBehavior(Handler handler, PhenotypeHelper phenotypeHelper) {
+    @Inject
+    AssistHandleReminderExpBehavior(
+            @Named(UPTIME_NAME) Clock clock,
+            @Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
+            PhenotypeHelper phenotypeHelper,
+            Lazy<StatusBarStateController> statusBarStateController,
+            Lazy<ActivityManagerWrapper> activityManagerWrapper,
+            Lazy<OverviewProxyService> overviewProxyService,
+            Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
+            Lazy<PackageManagerWrapper> packageManagerWrapper) {
+        mClock = clock;
         mHandler = handler;
         mPhenotypeHelper = phenotypeHelper;
-        mStatusBarStateController = Dependency.get(StatusBarStateController.class);
-        mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
-        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+        mStatusBarStateController = statusBarStateController;
+        mActivityManagerWrapper = activityManagerWrapper;
+        mOverviewProxyService = overviewProxyService;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
+        mPackageManagerWrapper = packageManagerWrapper;
         mDefaultHomeIntentFilter = new IntentFilter();
         for (String action : DEFAULT_HOME_CHANGE_ACTIONS) {
             mDefaultHomeIntentFilter.addAction(action);
@@ -167,13 +199,16 @@
         mConsecutiveTaskSwitches = 0;
         mDefaultHome = getCurrentDefaultHome();
         context.registerReceiver(mDefaultHomeBroadcastReceiver, mDefaultHomeIntentFilter);
-        mOnLockscreen = onLockscreen(mStatusBarStateController.getState());
-        mIsDozing = mStatusBarStateController.isDozing();
-        mStatusBarStateController.addCallback(mStatusBarStateListener);
-        ActivityManager.RunningTaskInfo runningTaskInfo = mActivityManagerWrapper.getRunningTask();
+        mOnLockscreen = onLockscreen(mStatusBarStateController.get().getState());
+        mStatusBarStateController.get().addCallback(mStatusBarStateListener);
+        ActivityManager.RunningTaskInfo runningTaskInfo =
+                mActivityManagerWrapper.get().getRunningTask();
         mRunningTaskId = runningTaskInfo == null ? 0 : runningTaskInfo.taskId;
-        mActivityManagerWrapper.registerTaskStackListener(mTaskStackChangeListener);
-        mOverviewProxyService.addCallback(mOverviewProxyListener);
+        mActivityManagerWrapper.get().registerTaskStackListener(mTaskStackChangeListener);
+        mOverviewProxyService.get().addCallback(mOverviewProxyListener);
+        mIsDozing = mWakefulnessLifecycle.get().getWakefulness()
+                != WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+        mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver);
 
         mLearningTimeElapsed = Settings.Secure.getLong(
                 context.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, /* default = */ 0);
@@ -181,7 +216,7 @@
                 context.getContentResolver(), LEARNING_EVENT_COUNT_KEY, /* default = */ 0);
         mLearnedHintLastShownEpochDay = Settings.Secure.getLong(
                 context.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, /* default = */ 0);
-        mLastLearningTimestamp = SystemClock.uptimeMillis();
+        mLastLearningTimestamp = mClock.currentTimeMillis();
 
         callbackForCurrentState(/* justUnlocked = */ false);
     }
@@ -196,9 +231,10 @@
             Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0);
             mContext = null;
         }
-        mStatusBarStateController.removeCallback(mStatusBarStateListener);
-        mActivityManagerWrapper.unregisterTaskStackListener(mTaskStackChangeListener);
-        mOverviewProxyService.removeCallback(mOverviewProxyListener);
+        mStatusBarStateController.get().removeCallback(mStatusBarStateListener);
+        mActivityManagerWrapper.get().unregisterTaskStackListener(mTaskStackChangeListener);
+        mOverviewProxyService.get().removeCallback(mOverviewProxyListener);
+        mWakefulnessLifecycle.get().removeObserver(mWakefulnessLifecycleObserver);
     }
 
     @Override
@@ -218,15 +254,10 @@
         }
     }
 
-    private static boolean isNavBarHidden(int sysuiStateFlags) {
-        return (sysuiStateFlags & QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
-    }
-
     @Nullable
-    private static ComponentName getCurrentDefaultHome() {
+    private ComponentName getCurrentDefaultHome() {
         List<ResolveInfo> homeActivities = new ArrayList<>();
-        ComponentName defaultHome =
-                PackageManagerWrapper.getInstance().getHomeActivities(homeActivities);
+        ComponentName defaultHome = mPackageManagerWrapper.get().getHomeActivities(homeActivities);
         if (defaultHome != null) {
             return defaultHome;
         }
@@ -282,7 +313,8 @@
     }
 
     private void handleSystemUiStateChanged(int sysuiStateFlags) {
-        boolean isNavBarHidden = isNavBarHidden(sysuiStateFlags);
+        boolean isNavBarHidden =
+                (sysuiStateFlags & QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
         if (mIsNavBarHidden == isNavBarHidden) {
             return;
         }
@@ -369,21 +401,15 @@
             return;
         }
 
-        long currentTimestamp = SystemClock.uptimeMillis();
+        long currentTimestamp = mClock.currentTimeMillis();
         mLearningTimeElapsed += currentTimestamp - mLastLearningTimestamp;
         mLastLearningTimestamp = currentTimestamp;
 
         mIsLearned =
                 mLearningCount >= getLearningCount() || mLearningTimeElapsed >= getLearningTimeMs();
 
-        mHandler.post(this::recordLearnTimeElapsed);
-    }
-
-    private void recordLearnTimeElapsed() {
-        if (mContext != null) {
-            Settings.Secure.putLong(
-                    mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed);
-        }
+        mHandler.post(() -> Settings.Secure.putLong(
+                mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed));
     }
 
     private void resetConsecutiveTaskSwitches() {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index ffe3cc04..1a2d062 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -19,7 +19,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -155,17 +154,18 @@
     };
 
     @Inject
-    public AssistManager(DeviceProvisionedController controller, Context context) {
+    public AssistManager(
+            DeviceProvisionedController controller,
+            Context context,
+            AssistUtils assistUtils,
+            AssistHandleBehaviorController handleController) {
         mContext = context;
         mDeviceProvisionedController = controller;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-        mAssistUtils = new AssistUtils(context);
+        mAssistUtils = assistUtils;
         mAssistDisclosure = new AssistDisclosure(context, new Handler());
         mPhoneStateMonitor = new PhoneStateMonitor(context);
-        final HandlerThread assistHandleThread = new HandlerThread("AssistHandleThread");
-        assistHandleThread.start();
-        mHandleController = new AssistHandleBehaviorController(
-                context, mAssistUtils, assistHandleThread.getThreadHandler());
+        mHandleController = handleController;
 
         registerVoiceInteractionSessionListener();
         mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
new file mode 100644
index 0000000..2a82d21
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java
@@ -0,0 +1,88 @@
+/*
+ * 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.assist;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.SystemClock;
+
+import androidx.slice.Clock;
+
+import com.android.internal.app.AssistUtils;
+import com.android.systemui.ScreenDecorations;
+import com.android.systemui.SysUiServiceProvider;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** Module for dagger injections related to the Assistant. */
+@Module
+public abstract class AssistModule {
+
+    static final String ASSIST_HANDLE_THREAD_NAME = "assist_handle_thread";
+    static final String UPTIME_NAME = "uptime";
+
+    @Provides
+    @Singleton
+    @Named(ASSIST_HANDLE_THREAD_NAME)
+    static Handler provideBackgroundHandler() {
+        final HandlerThread backgroundHandlerThread =
+                new HandlerThread("AssistHandleThread");
+        backgroundHandlerThread.start();
+        return backgroundHandlerThread.getThreadHandler();
+    }
+
+    @Provides
+    @Singleton
+    static Map<AssistHandleBehavior, AssistHandleBehaviorController.BehaviorController>
+            provideAssistHandleBehaviorControllerMap(
+                    AssistHandleOffBehavior offBehavior,
+                    AssistHandleLikeHomeBehavior likeHomeBehavior,
+                    AssistHandleReminderExpBehavior reminderExpBehavior) {
+        Map<AssistHandleBehavior, AssistHandleBehaviorController.BehaviorController> map =
+                new EnumMap<>(AssistHandleBehavior.class);
+        map.put(AssistHandleBehavior.OFF, offBehavior);
+        map.put(AssistHandleBehavior.LIKE_HOME, likeHomeBehavior);
+        map.put(AssistHandleBehavior.REMINDER_EXP, reminderExpBehavior);
+        return map;
+    }
+
+    @Provides
+    static ScreenDecorations provideScreenDecorations(Context context) {
+        return SysUiServiceProvider.getComponent(context, ScreenDecorations.class);
+    }
+
+    @Provides
+    @Singleton
+    static AssistUtils provideAssistUtils(Context context) {
+        return new AssistUtils(context);
+    }
+
+    @Provides
+    @Singleton
+    @Named(UPTIME_NAME)
+    static Clock provideSystemClock() {
+        return SystemClock::uptimeMillis;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java b/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
index b3f57af..ff76adf 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
@@ -22,8 +22,18 @@
 
 import java.util.concurrent.Executor;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Wrapper class for retrieving phenotype flag values.
+ *
+ * Can be mocked in tests for ease of testing the effects of particular values.
+ */
+@Singleton
 public class PhenotypeHelper {
 
+    @Inject
     public PhenotypeHelper() {}
 
     public long getLong(String name, long defaultValue) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
index a583b1c..20983fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
@@ -37,10 +37,12 @@
 
 import com.android.internal.app.AssistUtils;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.systemui.DumpController;
 import com.android.systemui.ScreenDecorations;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.statusbar.phone.NavigationModeController;
 
 import org.junit.After;
 import org.junit.Before;
@@ -50,6 +52,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.EnumMap;
+import java.util.Map;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -63,7 +68,12 @@
     @Mock private AssistUtils mMockAssistUtils;
     @Mock private Handler mMockHandler;
     @Mock private PhenotypeHelper mMockPhenotypeHelper;
-    @Mock private AssistHandleBehaviorController.BehaviorController mMockBehaviorController;
+    @Mock private AssistHandleOffBehavior mMockOffBehavior;
+    @Mock private AssistHandleLikeHomeBehavior mMockLikeHomeBehavior;
+    @Mock private AssistHandleReminderExpBehavior mMockReminderExpBehavior;
+    @Mock private AssistHandleBehaviorController.BehaviorController mMockTestBehavior;
+    @Mock private NavigationModeController mMockNavigationModeController;
+    @Mock private DumpController mMockDumpController;
 
     @Before
     public void setup() {
@@ -74,13 +84,23 @@
         doAnswer(answerVoid(Runnable::run)).when(mMockHandler)
                 .postDelayed(any(Runnable.class), anyLong());
 
+        Map<AssistHandleBehavior, AssistHandleBehaviorController.BehaviorController> behaviorMap =
+                new EnumMap<>(AssistHandleBehavior.class);
+        behaviorMap.put(AssistHandleBehavior.OFF, mMockOffBehavior);
+        behaviorMap.put(AssistHandleBehavior.LIKE_HOME, mMockLikeHomeBehavior);
+        behaviorMap.put(AssistHandleBehavior.REMINDER_EXP, mMockReminderExpBehavior);
+        behaviorMap.put(AssistHandleBehavior.TEST, mMockTestBehavior);
+
         mAssistHandleBehaviorController =
                 new AssistHandleBehaviorController(
                         mContext,
                         mMockAssistUtils,
-                        mMockHandler, () -> mMockScreenDecorations,
+                        mMockHandler,
+                        () -> mMockScreenDecorations,
                         mMockPhenotypeHelper,
-                        mMockBehaviorController);
+                        behaviorMap,
+                        mMockNavigationModeController,
+                        mMockDumpController);
     }
 
     @After
@@ -314,8 +334,8 @@
         mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.TEST);
 
         // Assert
-        verify(mMockBehaviorController).onModeActivated(mContext, mAssistHandleBehaviorController);
-        verifyNoMoreInteractions(mMockBehaviorController);
+        verify(mMockTestBehavior).onModeActivated(mContext, mAssistHandleBehaviorController);
+        verifyNoMoreInteractions(mMockTestBehavior);
     }
 
     @Test
@@ -324,14 +344,14 @@
         when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
         mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.TEST);
         mAssistHandleBehaviorController.setInGesturalModeForTest(true);
-        reset(mMockBehaviorController);
+        reset(mMockTestBehavior);
 
         // Act
         mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.OFF);
 
         // Assert
-        verify(mMockBehaviorController).onModeDeactivated();
-        verifyNoMoreInteractions(mMockBehaviorController);
+        verify(mMockTestBehavior).onModeDeactivated();
+        verifyNoMoreInteractions(mMockTestBehavior);
     }
 
     @Test
@@ -344,6 +364,6 @@
         mAssistHandleBehaviorController.setBehavior(AssistHandleBehavior.TEST);
 
         // Assert
-        verifyNoMoreInteractions(mMockBehaviorController);
+        verifyNoMoreInteractions(mMockTestBehavior);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleLikeHomeBehaviorTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleLikeHomeBehaviorTest.java
new file mode 100644
index 0000000..2aa866e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleLikeHomeBehaviorTest.java
@@ -0,0 +1,251 @@
+/*
+ * 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.assist;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.system.QuickStepContract;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AssistHandleLikeHomeBehaviorTest extends SysuiTestCase {
+
+    private AssistHandleLikeHomeBehavior mAssistHandleLikeHomeBehavior;
+
+    @Mock private WakefulnessLifecycle mMockWakefulnessLifecycle;
+    @Mock private OverviewProxyService mMockOverviewProxyService;
+    @Mock private AssistHandleCallbacks mMockAssistHandleCallbacks;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mAssistHandleLikeHomeBehavior = new AssistHandleLikeHomeBehavior(
+                () -> mMockWakefulnessLifecycle, () -> mMockOverviewProxyService);
+    }
+
+    @Test
+    public void onModeActivated_beginsObserving() {
+        // Arrange
+
+        // Act
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+
+        // Assert
+        verify(mMockWakefulnessLifecycle).getWakefulness();
+        verify(mMockWakefulnessLifecycle).addObserver(any(WakefulnessLifecycle.Observer.class));
+        verify(mMockOverviewProxyService).addCallback(any(
+                OverviewProxyService.OverviewProxyListener.class));
+        verifyNoMoreInteractions(mMockWakefulnessLifecycle, mMockOverviewProxyService);
+    }
+
+    @Test
+    public void onModeActivated_showsHandlesWhenAwake() {
+        // Arrange
+        when(mMockWakefulnessLifecycle.getWakefulness())
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+
+        // Act
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+
+        // Assert
+        verify(mMockAssistHandleCallbacks).showAndStay();
+        verifyNoMoreInteractions(mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onModeActivated_hidesHandlesWhenNotAwake() {
+        // Arrange
+        when(mMockWakefulnessLifecycle.getWakefulness())
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP);
+
+        // Act
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+
+        // Assert
+        verify(mMockAssistHandleCallbacks).hide();
+        verifyNoMoreInteractions(mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onModeDeactivated_stopsObserving() {
+        // Arrange
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        ArgumentCaptor<WakefulnessLifecycle.Observer> observer =
+                ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
+        ArgumentCaptor<OverviewProxyService.OverviewProxyListener> overviewProxyListener =
+                ArgumentCaptor.forClass(OverviewProxyService.OverviewProxyListener.class);
+        verify(mMockWakefulnessLifecycle).addObserver(observer.capture());
+        verify(mMockOverviewProxyService).addCallback(overviewProxyListener.capture());
+        reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        mAssistHandleLikeHomeBehavior.onModeDeactivated();
+
+        // Assert
+        verify(mMockWakefulnessLifecycle).removeObserver(eq(observer.getValue()));
+        verify(mMockOverviewProxyService).removeCallback(eq(overviewProxyListener.getValue()));
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onAssistantGesturePerformed_doesNothing() {
+        // Arrange
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        mAssistHandleLikeHomeBehavior.onAssistantGesturePerformed();
+
+        // Assert
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onAssistHandlesRequested_doesNothing() {
+        // Arrange
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        mAssistHandleLikeHomeBehavior.onAssistHandlesRequested();
+
+        // Assert
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onWake_handlesShow() {
+        // Arrange
+        when(mMockWakefulnessLifecycle.getWakefulness())
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP);
+        ArgumentCaptor<WakefulnessLifecycle.Observer> observer =
+                ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        verify(mMockWakefulnessLifecycle).addObserver(observer.capture());
+        reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        observer.getValue().onStartedWakingUp();
+
+        // Assert
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        observer.getValue().onFinishedWakingUp();
+
+        // Assert
+        verify(mMockAssistHandleCallbacks).showAndStay();
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onSleep_handlesHide() {
+        // Arrange
+        when(mMockWakefulnessLifecycle.getWakefulness())
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+        ArgumentCaptor<WakefulnessLifecycle.Observer> observer =
+                ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        verify(mMockWakefulnessLifecycle).addObserver(observer.capture());
+        reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        observer.getValue().onStartedGoingToSleep();
+
+        // Assert
+        verify(mMockAssistHandleCallbacks).hide();
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        observer.getValue().onFinishedGoingToSleep();
+
+        // Assert
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onHomeHandleHide_handlesHide() {
+        // Arrange
+        when(mMockWakefulnessLifecycle.getWakefulness())
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+        ArgumentCaptor<OverviewProxyService.OverviewProxyListener> sysUiStateCallback =
+                ArgumentCaptor.forClass(OverviewProxyService.OverviewProxyListener.class);
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        verify(mMockOverviewProxyService).addCallback(sysUiStateCallback.capture());
+        reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        sysUiStateCallback.getValue().onSystemUiStateChanged(
+                QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN);
+
+        // Assert
+        verify(mMockAssistHandleCallbacks).hide();
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onHomeHandleUnhide_handlesShow() {
+        // Arrange
+        when(mMockWakefulnessLifecycle.getWakefulness())
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+        ArgumentCaptor<OverviewProxyService.OverviewProxyListener> sysUiStateCallback =
+                ArgumentCaptor.forClass(OverviewProxyService.OverviewProxyListener.class);
+        mAssistHandleLikeHomeBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        verify(mMockOverviewProxyService).addCallback(sysUiStateCallback.capture());
+        sysUiStateCallback.getValue().onSystemUiStateChanged(
+                QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN);
+        reset(mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+
+        // Act
+        sysUiStateCallback.getValue().onSystemUiStateChanged(
+                ~QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN);
+
+        // Assert
+        verify(mMockAssistHandleCallbacks).showAndStay();
+        verifyNoMoreInteractions(
+                mMockWakefulnessLifecycle, mMockOverviewProxyService, mMockAssistHandleCallbacks);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleOffBehaviorTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleOffBehaviorTest.java
new file mode 100644
index 0000000..15d4d5b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleOffBehaviorTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.assist;
+
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AssistHandleOffBehaviorTest extends SysuiTestCase {
+
+    private AssistHandleOffBehavior mAssistHandleOffBehavior;
+
+    @Mock private AssistHandleCallbacks mMockAssistHandleCallbacks;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mAssistHandleOffBehavior = new AssistHandleOffBehavior();
+    }
+
+    @Test
+    public void onModeActivated_hidesHandles() {
+        // Arrange
+
+        // Act
+        mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+
+        // Assert
+        verify(mMockAssistHandleCallbacks).hide();
+        verifyNoMoreInteractions(mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onModeDeactivated_doesNothing() {
+        // Arrange
+        mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        reset(mMockAssistHandleCallbacks);
+
+        // Act
+        mAssistHandleOffBehavior.onModeDeactivated();
+
+        // Assert
+        verifyNoMoreInteractions(mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onAssistantGesturePerformed_doesNothing() {
+        // Arrange
+        mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        reset(mMockAssistHandleCallbacks);
+
+        // Act
+        mAssistHandleOffBehavior.onAssistantGesturePerformed();
+
+        // Assert
+        verifyNoMoreInteractions(mMockAssistHandleCallbacks);
+    }
+
+    @Test
+    public void onAssistHandlesRequested_doesNothing() {
+        // Arrange
+        mAssistHandleOffBehavior.onModeActivated(mContext, mMockAssistHandleCallbacks);
+        reset(mMockAssistHandleCallbacks);
+
+        // Act
+        mAssistHandleOffBehavior.onAssistHandlesRequested();
+
+        // Assert
+        verifyNoMoreInteractions(mMockAssistHandleCallbacks);
+    }
+}