diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java index 616e56288392e..3def945dd03c5 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java @@ -28,7 +28,6 @@ import com.android.systemui.car.window.SystemUIOverlayWindowManager; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.dagger.KeyguardModule; -import com.android.systemui.onehanded.OneHandedUI; import com.android.systemui.power.PowerUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; @@ -94,12 +93,6 @@ public abstract class CarSystemUIBinder { @ClassKey(LatencyTester.class) public abstract SystemUI bindLatencyTester(LatencyTester sysui); - /** Inject into OneHandedUI. */ - @Binds - @IntoMap - @ClassKey(OneHandedUI.class) - public abstract SystemUI bindOneHandedUI(OneHandedUI sysui); - /** Inject into PowerUI. */ @Binds @IntoMap diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md index bd93c396aa163..ee8d02301d5d3 100644 --- a/packages/SystemUI/README.md +++ b/packages/SystemUI/README.md @@ -111,10 +111,6 @@ Plays ringtones. Shows UI for keyboard shortcuts (triggered by keyboard shortcut). -### [com.android.systemui.onehanded.OneHandedUI](/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java) - -Shows the overlay controls when One handed is triggered. - ### [com.android.systemui.shortcut.ShortcutKeyDispatcher](/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java) Dispatches shortcut to System UI components. diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 4a94038f4533a..66304013da460 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -39,7 +39,6 @@ com.android.systemui.SizeCompatModeActivityController com.android.systemui.statusbar.notification.InstantAppNotifier com.android.systemui.toast.ToastUI - com.android.systemui.onehanded.OneHandedUI com.android.systemui.wmshell.WMShell diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 7faa2a44bb6cc..0cc0dfd19fdfe 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -320,7 +320,6 @@ com.android.systemui.accessibility.WindowMagnification com.android.systemui.accessibility.SystemActions com.android.systemui.toast.ToastUI - com.android.systemui.onehanded.OneHandedUI com.android.systemui.wmshell.WMShell diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index c331bd377eecc..3a5ce4d82540e 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -28,7 +28,6 @@ import com.android.systemui.bubbles.dagger.BubbleModule; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.dagger.KeyguardModule; -import com.android.systemui.onehanded.OneHandedUI; import com.android.systemui.power.PowerUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; @@ -90,12 +89,6 @@ public abstract class SystemUIBinder { @ClassKey(LatencyTester.class) public abstract SystemUI bindLatencyTester(LatencyTester sysui); - /** Inject into OneHandedUI. */ - @Binds - @IntoMap - @ClassKey(OneHandedUI.class) - public abstract SystemUI bindOneHandedUI(OneHandedUI sysui); - /** Inject into PowerUI. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHanded.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHanded.java new file mode 100644 index 0000000000000..b7c6262b07e0b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHanded.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.onehanded; + +import androidx.annotation.NonNull; + +import com.android.systemui.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback; + +import java.io.PrintWriter; + +/** + * Interface to engage one handed feature. + */ +public interface OneHanded { + /** + * Return whether the device has one handed feature or not. + */ + boolean hasOneHandedFeature(); + + /** + * Return one handed settings enabled or not. + */ + boolean isOneHandedEnabled(); + + /** + * Return swipe to notification settings enabled or not. + */ + boolean isSwipeToNotificationEnabled(); + + /** + * Enters one handed mode. + */ + void startOneHanded(); + + /** + * Exits one handed mode. + */ + void stopOneHanded(); + + /** + * Exits one handed mode with {@link OneHandedEvents}. + */ + void stopOneHanded(int event); + + /** + * Set navigation 3 button mode enabled or disabled by users. + */ + void setThreeButtonModeEnabled(boolean enabled); + + /** + * Register callback to be notified after {@link OneHandedDisplayAreaOrganizer} + * transition start or finish + */ + void registerTransitionCallback(OneHandedTransitionCallback callback); + + /** + * Register callback for one handed gesture, this gesture callbcak will be activated on + * 3 button navigation mode only + */ + void registerGestureCallback(OneHandedGestureEventCallback callback); + + /** + * Dump one handed status. + */ + void dump(@NonNull PrintWriter pw); +} diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java index bb59449d114da..90adf838440c9 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedController.java @@ -16,82 +16,61 @@ package com.android.systemui.onehanded; +import static android.os.UserHandle.USER_CURRENT; import static android.view.Display.DEFAULT_DISPLAY; -import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE; - -import android.content.ComponentName; import android.content.Context; +import android.content.om.IOverlayManager; +import android.content.om.OverlayInfo; +import android.database.ContentObserver; import android.graphics.Point; -import android.graphics.Rect; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemProperties; -import android.view.KeyEvent; +import android.provider.Settings; +import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dumpable; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.model.SysUiState; -import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.TaskStackChangeListener; -import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; -import java.io.FileDescriptor; import java.io.PrintWriter; -import javax.inject.Inject; - /** * Manages and manipulates the one handed states, transitions, and gesture for phones. */ -@SysUISingleton -public class OneHandedController implements Dumpable { - private static final String TAG = "OneHandedManager"; +public class OneHandedController implements OneHanded { + private static final String TAG = "OneHandedController"; + private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = "persist.debug.one_handed_offset_percentage"; + private static final String ONE_HANDED_MODE_GESTURAL_OVERLAY = + "com.android.internal.systemui.onehanded.gestural"; + static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; + + private final boolean mHasOneHandedFeature; private boolean mIsOneHandedEnabled; private boolean mIsSwipeToNotificationEnabled; private boolean mTaskChangeToExit; private float mOffSetFraction; - private final CommandQueue mCommandQueue; + private final Context mContext; private final DisplayController mDisplayController; private final OneHandedGestureHandler mGestureHandler; private final OneHandedTimeoutHandler mTimeoutHandler; private final OneHandedTouchHandler mTouchHandler; private final OneHandedTutorialHandler mTutorialHandler; - private final SysUiState mSysUiFlagContainer; + private final IOverlayManager mOverlayManager; + private final Handler mMainHandler = new Handler(Looper.getMainLooper()); private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer; - /** - * Handler for system task stack changes, exit when user lunch new task or bring task to front - */ - private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { - @Override - public void onTaskCreated(int taskId, ComponentName componentName) { - if (!mIsOneHandedEnabled || !mDisplayAreaOrganizer.isInOneHanded()) { - return; - } - OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT); - stopOneHanded(); - } - - @Override - public void onTaskMovedToFront(int taskId) { - if (!mIsOneHandedEnabled || !mDisplayAreaOrganizer.isInOneHanded()) { - return; - } - OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT); - stopOneHanded(); - } - }; - /** * Handle rotation based on OnDisplayChangingListener callback */ @@ -102,109 +81,197 @@ public class OneHandedController implements Dumpable { } }; - /** - * Constructor of OneHandedManager - */ - @Inject - public OneHandedController(Context context, - CommandQueue commandQueue, - DisplayController displayController, - NavigationModeController navigationModeController, - SysUiState sysUiState) { - mCommandQueue = commandQueue; - mDisplayController = displayController; - mDisplayController.addDisplayChangingController(mRotationController); - mSysUiFlagContainer = sysUiState; - mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f; + private final ContentObserver mEnabledObserver = new ContentObserver(mMainHandler) { + @Override + public void onChange(boolean selfChange) { + final boolean enabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( + mContext.getContentResolver()); + OneHandedEvents.writeEvent(enabled + ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON + : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF); - mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - context.getContentResolver()); - mIsSwipeToNotificationEnabled = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( - context.getContentResolver()); - mTimeoutHandler = OneHandedTimeoutHandler.get(); - mTouchHandler = new OneHandedTouchHandler(); - mTutorialHandler = new OneHandedTutorialHandler(context); - mDisplayAreaOrganizer = new OneHandedDisplayAreaOrganizer(context, displayController, - new OneHandedAnimationController(context), mTutorialHandler); - mGestureHandler = new OneHandedGestureHandler( - context, displayController, navigationModeController); - updateOneHandedEnabled(); - setupGestures(); + setOneHandedEnabled(enabled); + + // Also checks swipe to notification settings since they all need gesture overlay. + setEnabledGesturalOverlay( + enabled || OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + mContext.getContentResolver())); + } + }; + + private final ContentObserver mTimeoutObserver = new ContentObserver(mMainHandler) { + @Override + public void onChange(boolean selfChange) { + final int newTimeout = OneHandedSettingsUtil.getSettingsOneHandedModeTimeout( + mContext.getContentResolver()); + int metricsId = OneHandedEvents.OneHandedSettingsTogglesEvent.INVALID.getId(); + switch (newTimeout) { + case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER: + metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER; + break; + case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS: + metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4; + break; + case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS: + metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8; + break; + case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_LONG_IN_SECONDS: + metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12; + break; + default: + // do nothing + break; + } + OneHandedEvents.writeEvent(metricsId); + + if (mTimeoutHandler != null) { + mTimeoutHandler.setTimeout(newTimeout); + } + } + }; + + private final ContentObserver mTaskChangeExitObserver = new ContentObserver(mMainHandler) { + @Override + public void onChange(boolean selfChange) { + final boolean enabled = OneHandedSettingsUtil.getSettingsTapsAppToExit( + mContext.getContentResolver()); + OneHandedEvents.writeEvent(enabled + ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON + : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF); + + setTaskChangeToExit(enabled); + } + }; + + private final ContentObserver mSwipeToNotificationEnabledObserver = + new ContentObserver(mMainHandler) { + @Override + public void onChange(boolean selfChange) { + final boolean enabled = + OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + mContext.getContentResolver()); + setSwipeToNotificationEnabled(enabled); + + // Also checks one handed mode settings since they all need gesture overlay. + setEnabledGesturalOverlay( + enabled || OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( + mContext.getContentResolver())); + } + }; + + /** + * The static constructor method to create OneHnadedController. + */ + public static OneHandedController create( + Context context, DisplayController displayController) { + OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context); + OneHandedAnimationController animationController = + new OneHandedAnimationController(context); + OneHandedTouchHandler touchHandler = new OneHandedTouchHandler(); + OneHandedGestureHandler gestureHandler = new OneHandedGestureHandler( + context, displayController); + OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer( + context, displayController, animationController, tutorialHandler); + return new OneHandedController(context, displayController, organizer, touchHandler, + tutorialHandler, gestureHandler); } - /** - * Constructor of OneHandedManager for testing - */ - // TODO(b/161980408): Should remove extra constructor. @VisibleForTesting OneHandedController(Context context, - CommandQueue commandQueue, DisplayController displayController, OneHandedDisplayAreaOrganizer displayAreaOrganizer, OneHandedTouchHandler touchHandler, OneHandedTutorialHandler tutorialHandler, - OneHandedGestureHandler gestureHandler, - SysUiState sysUiState) { - mCommandQueue = commandQueue; + OneHandedGestureHandler gestureHandler) { + mHasOneHandedFeature = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false); + if (!mHasOneHandedFeature) { + Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off"); + mContext = null; + mDisplayAreaOrganizer = null; + mDisplayController = null; + mTouchHandler = null; + mTutorialHandler = null; + mGestureHandler = null; + mTimeoutHandler = null; + mOverlayManager = null; + return; + } + + mContext = context; mDisplayAreaOrganizer = displayAreaOrganizer; mDisplayController = displayController; - mDisplayController.addDisplayChangingController(mRotationController); - mSysUiFlagContainer = sysUiState; - mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f; + mTouchHandler = touchHandler; + mTutorialHandler = tutorialHandler; + mGestureHandler = gestureHandler; + mOverlayManager = IOverlayManager.Stub.asInterface( + ServiceManager.getService(Context.OVERLAY_SERVICE)); + mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f; mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( context.getContentResolver()); mIsSwipeToNotificationEnabled = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( context.getContentResolver()); mTimeoutHandler = OneHandedTimeoutHandler.get(); - mTouchHandler = touchHandler; - mTutorialHandler = tutorialHandler; - mGestureHandler = gestureHandler; - updateOneHandedEnabled(); - setupGestures(); + + mDisplayController.addDisplayChangingController(mRotationController); + + setupCallback(); + setupSettingObservers(); + setupTimeoutListener(); + setupGesturalOverlay(); + updateSettings(); } /** - * Set one handed enabled or disabled by OneHanded UI when user update settings + * Set one handed enabled or disabled when user update settings */ - public void setOneHandedEnabled(boolean enabled) { + void setOneHandedEnabled(boolean enabled) { mIsOneHandedEnabled = enabled; updateOneHandedEnabled(); } /** - * Set one handed enabled or disabled by OneHanded UI when user update settings + * Set one handed enabled or disabled by when user update settings */ - public void setTaskChangeToExit(boolean enabled) { - if (mTaskChangeToExit == enabled) { - return; - } + void setTaskChangeToExit(boolean enabled) { mTaskChangeToExit = enabled; - updateOneHandedEnabled(); } /** * Sets whether to enable swipe bottom to notification gesture when user update settings. */ - public void setSwipeToNotificationEnabled(boolean enabled) { + void setSwipeToNotificationEnabled(boolean enabled) { mIsSwipeToNotificationEnabled = enabled; updateOneHandedEnabled(); } - /** - * Enters one handed mode. - */ + @Override + public boolean hasOneHandedFeature() { + return mHasOneHandedFeature; + } + + @Override + public boolean isOneHandedEnabled() { + return mIsOneHandedEnabled; + } + + @Override + public boolean isSwipeToNotificationEnabled() { + return mIsSwipeToNotificationEnabled; + } + + @Override public void startOneHanded() { if (!mDisplayAreaOrganizer.isInOneHanded()) { final int yOffSet = Math.round(getDisplaySize().y * mOffSetFraction); mDisplayAreaOrganizer.scheduleOffset(0, yOffSet); mTimeoutHandler.resetTimer(); + + OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN); } } - /** - * Exits one handed mode. - */ + @Override public void stopOneHanded() { if (mDisplayAreaOrganizer.isInOneHanded()) { mDisplayAreaOrganizer.scheduleOffset(0, 0); @@ -212,64 +279,72 @@ public class OneHandedController implements Dumpable { } } - private void setupGestures() { - mTouchHandler.registerTouchEventListener( - new OneHandedTouchHandler.OneHandedTouchEventCallback() { - @Override - public void onStart() { - if (mIsOneHandedEnabled) { - startOneHanded(); - } - } + @Override + public void stopOneHanded(int event) { + if (!mTaskChangeToExit && event == OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT) { + //Task change exit not enable, do nothing and return here. + return; + } - @Override - public void onStop() { - if (mIsOneHandedEnabled) { - stopOneHanded(); - } - } - }); + if (mDisplayAreaOrganizer.isInOneHanded()) { + OneHandedEvents.writeEvent(event); + } - mGestureHandler.setGestureEventListener( - new OneHandedGestureHandler.OneHandedGestureEventCallback() { - @Override - public void onStart() { - if (mIsOneHandedEnabled) { - startOneHanded(); - } else if (mIsSwipeToNotificationEnabled) { - mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN); - } - } + stopOneHanded(); + } - @Override - public void onStop() { - if (mIsOneHandedEnabled) { - stopOneHanded(); - } else if (mIsSwipeToNotificationEnabled) { - mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP); - } - } - }); + @Override + public void setThreeButtonModeEnabled(boolean enabled) { + mGestureHandler.onThreeButtonModeEnabled(enabled); + } - mDisplayAreaOrganizer.registerTransitionCallback(new OneHandedTransitionCallback() { - @Override - public void onStartFinished(Rect bounds) { - mSysUiFlagContainer.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE, - true).commitUpdate(DEFAULT_DISPLAY); - } + @Override + public void registerTransitionCallback(OneHandedTransitionCallback callback) { + mDisplayAreaOrganizer.registerTransitionCallback(callback); + } - @Override - public void onStopFinished(Rect bounds) { - mSysUiFlagContainer.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE, - false).commitUpdate(DEFAULT_DISPLAY); - } - }); + @Override + public void registerGestureCallback(OneHandedGestureEventCallback callback) { + mGestureHandler.setGestureEventListener(callback); + } + private void setupCallback() { + mTouchHandler.registerTouchEventListener(() -> + stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_OVERSPACE_OUT)); mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler); mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler); mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler); } + private void setupSettingObservers() { + OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED, + mContext.getContentResolver(), mEnabledObserver); + OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT, + mContext.getContentResolver(), mTimeoutObserver); + OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT, + mContext.getContentResolver(), mTaskChangeExitObserver); + OneHandedSettingsUtil.registerSettingsKeyObserver( + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, + mContext.getContentResolver(), mSwipeToNotificationEnabledObserver); + } + + private void updateSettings() { + setOneHandedEnabled(OneHandedSettingsUtil + .getSettingsOneHandedModeEnabled(mContext.getContentResolver())); + mTimeoutHandler.setTimeout(OneHandedSettingsUtil + .getSettingsOneHandedModeTimeout(mContext.getContentResolver())); + setTaskChangeToExit(OneHandedSettingsUtil + .getSettingsTapsAppToExit(mContext.getContentResolver())); + setSwipeToNotificationEnabled(OneHandedSettingsUtil + .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver())); + } + + private void setupTimeoutListener() { + mTimeoutHandler.registerTimeoutListener(timeoutTime -> { + stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT); + }); + } + /** * Query the current display real size from {@link DisplayController} * @@ -293,25 +368,73 @@ public class OneHandedController implements Dumpable { mDisplayAreaOrganizer.registerOrganizer( OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED); } - ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener); - if (mTaskChangeToExit) { - ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); - } mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled); mGestureHandler.onOneHandedEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled); } + private void setupGesturalOverlay() { + if (!OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver())) { + return; + } + + OverlayInfo info = null; + try { + // TODO(b/157958539) migrate new RRO config file after S+ + mOverlayManager.setHighestPriority(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT); + info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT); + } catch (RemoteException e) { /* Do nothing */ } + + if (info != null && !info.isEnabled()) { + // Enable the default gestural one handed overlay. + setEnabledGesturalOverlay(true); + } + } + + @androidx.annotation.VisibleForTesting + private void setEnabledGesturalOverlay(boolean enabled) { + try { + mOverlayManager.setEnabled(ONE_HANDED_MODE_GESTURAL_OVERLAY, enabled, USER_CURRENT); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @Override - public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + public void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG + "states: "); - pw.print(innerPrefix + "mSysUiFlagContainer="); - pw.println(mSysUiFlagContainer.getFlags()); pw.print(innerPrefix + "mOffSetFraction="); pw.println(mOffSetFraction); if (mDisplayAreaOrganizer != null) { - mDisplayAreaOrganizer.dump(fd, pw, args); + mDisplayAreaOrganizer.dump(pw); + } + + if (mTouchHandler != null) { + mTouchHandler.dump(pw); + } + + if (mTimeoutHandler != null) { + mTimeoutHandler.dump(pw); + } + + if (mTutorialHandler != null) { + mTutorialHandler.dump(pw); + } + + OneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver()); + + if (mOverlayManager != null) { + OverlayInfo info = null; + try { + info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY, + USER_CURRENT); + } catch (RemoteException e) { /* Do nothing */ } + + if (info != null && !info.isEnabled()) { + pw.print(innerPrefix + "OverlayInfo="); + pw.println(info); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java index ad9f7ea4e9458..ec40bad06b717 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java @@ -38,10 +38,8 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.os.SomeArgs; -import com.android.systemui.Dumpable; import com.android.wm.shell.common.DisplayController; -import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; @@ -58,7 +56,7 @@ import java.util.Objects; * * This class is also responsible for translating one handed operations within SysUI component */ -public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implements Dumpable { +public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { private static final String TAG = "OneHandedDisplayAreaOrganizer"; private static final String ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION = "persist.debug.one_handed_translate_animation_duration"; @@ -353,8 +351,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen return args; } - @Override - public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG + "states: "); pw.print(innerPrefix + "mIsInOneHanded="); diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java index f3be699ab8215..4a493ba800ba7 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java @@ -17,7 +17,6 @@ package com.android.systemui.onehanded; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import android.annotation.Nullable; import android.content.Context; @@ -40,7 +39,6 @@ import android.window.WindowContainerTransaction; import androidx.annotation.VisibleForTesting; import com.android.systemui.R; -import com.android.systemui.navigationbar.NavigationModeController; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; @@ -49,7 +47,6 @@ import com.android.wm.shell.common.DisplayController; * others(e.g, 2-button, full gesture mode) are handled by Launcher quick steps. */ public class OneHandedGestureHandler implements OneHandedTransitionCallback, - NavigationModeController.ModeChangedListener, DisplayChangeController.OnDisplayChangingListener { private static final String TAG = "OneHandedGestureHandler"; private static final boolean DEBUG_GESTURE = false; @@ -66,7 +63,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, private boolean mAllowGesture; private boolean mIsEnabled; private int mNavGestureHeight; - private boolean mIsThreeButtonModeEnable; + private boolean mIsThreeButtonModeEnabled; private int mRotation = Surface.ROTATION_0; @VisibleForTesting @@ -85,14 +82,10 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, * * @param context {@link Context} * @param displayController {@link DisplayController} - * @param navigationModeController {@link NavigationModeController} */ - public OneHandedGestureHandler(Context context, DisplayController displayController, - NavigationModeController navigationModeController) { + public OneHandedGestureHandler(Context context, DisplayController displayController) { mDisplayController = displayController; displayController.addDisplayChangingController(this); - final int NavBarMode = navigationModeController.addListener(this); - mIsThreeButtonModeEnable = (NavBarMode == NAV_BAR_MODE_3BUTTON); mNavGestureHeight = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.navigation_bar_gesture_height); mDragDistThreshold = context.getResources().getDimensionPixelSize( @@ -115,6 +108,11 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, updateIsEnabled(); } + void onThreeButtonModeEnabled(boolean isEnabled) { + mIsThreeButtonModeEnabled = isEnabled; + updateIsEnabled(); + } + /** * Register {@link OneHandedGestureEventCallback} to receive onStart(), onStop() callback */ @@ -199,7 +197,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, private void updateIsEnabled() { disposeInputChannel(); - if (mIsEnabled && mIsThreeButtonModeEnable) { + if (mIsEnabled && mIsThreeButtonModeEnabled) { final Point displaySize = new Point(); if (mDisplayController != null) { final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY); @@ -223,15 +221,6 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } } - @Override - public void onNavigationModeChanged(int mode) { - if (DEBUG_GESTURE) { - Log.d(TAG, "onNavigationModeChanged, mode =" + mode); - } - mIsThreeButtonModeEnable = (mode == NAV_BAR_MODE_3BUTTON); - updateIsEnabled(); - } - @Override public void onRotateDisplay(int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) { diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java index 6bed30425c55f..21329ea1b0e62 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTimeoutHandler.java @@ -25,9 +25,6 @@ import android.os.Message; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import com.android.systemui.Dumpable; - -import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -36,7 +33,7 @@ import java.util.concurrent.TimeUnit; /** * Timeout handler for stop one handed mode operations. */ -public class OneHandedTimeoutHandler implements Dumpable { +public class OneHandedTimeoutHandler { private static final String TAG = "OneHandedTimeoutHandler"; private static boolean sIsDragging = false; // Default timeout is ONE_HANDED_TIMEOUT_MEDIUM @@ -150,8 +147,7 @@ public class OneHandedTimeoutHandler implements Dumpable { } } - @Override - public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG + "states: "); pw.print(innerPrefix + "sTimeout="); diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java index 8265da6a5f142..3d28a426f4f8e 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java @@ -30,9 +30,6 @@ import android.view.MotionEvent; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import com.android.systemui.Dumpable; - -import java.io.FileDescriptor; import java.io.PrintWriter; /** @@ -40,7 +37,7 @@ import java.io.PrintWriter; * to exit, reset timer when user is in one-handed mode. * Refer {@link OneHandedGestureHandler} to see start and stop one handed gesture */ -public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpable { +public class OneHandedTouchHandler implements OneHandedTransitionCallback { private static final String TAG = "OneHandedTouchHandler"; private final Rect mLastUpdatedBounds = new Rect(); @@ -146,8 +143,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa mIsOnStopTransitioning = false; } - @Override - public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG + "states: "); pw.print(innerPrefix + "mLastUpdatedBounds="); @@ -169,11 +165,6 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa * The touch(gesture) events to notify {@link OneHandedController} start or stop one handed */ public interface OneHandedTouchEventCallback { - /** - * Handle the start event. - */ - void onStart(); - /** * Handle the exit event. */ diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java index 8ef9b092bc009..beccf3dbc8deb 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java @@ -33,10 +33,8 @@ import android.widget.FrameLayout; import androidx.annotation.NonNull; -import com.android.systemui.Dumpable; import com.android.systemui.R; -import java.io.FileDescriptor; import java.io.PrintWriter; /** @@ -45,7 +43,7 @@ import java.io.PrintWriter; * Refer {@link OneHandedGestureHandler} and {@link OneHandedTouchHandler} to see start and stop * one handed gesture */ -public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable { +public class OneHandedTutorialHandler implements OneHandedTransitionCallback { private static final String TAG = "OneHandedTutorialHandler"; private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = "persist.debug.one_handed_offset_percentage"; @@ -170,8 +168,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du return lp; } - @Override - public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + void dump(@NonNull PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG + "states: "); pw.print(innerPrefix + "mLastUpdatedBounds="); diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java deleted file mode 100644 index 3348a06d5cac4..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.onehanded; - -import static android.os.UserHandle.USER_CURRENT; -import static android.view.Display.DEFAULT_DISPLAY; - -import android.content.Context; -import android.content.om.IOverlayManager; -import android.content.om.OverlayInfo; -import android.database.ContentObserver; -import android.inputmethodservice.InputMethodService; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemProperties; -import android.provider.Settings; -import android.util.Log; - -import androidx.annotation.VisibleForTesting; - -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.systemui.Dependency; -import com.android.systemui.Dumpable; -import com.android.systemui.SystemUI; -import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.statusbar.CommandQueue; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -import javax.inject.Inject; - -/** - * A service that controls UI of the one handed mode function. - */ -@SysUISingleton -public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dumpable { - private static final String TAG = "OneHandedUI"; - private static final String ONE_HANDED_MODE_GESTURAL_OVERLAY = - "com.android.internal.systemui.onehanded.gestural"; - private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; - - private final OneHandedController mOneHandedController; - private final CommandQueue mCommandQueue; - private final Handler mMainHandler = new Handler(Looper.getMainLooper()); - private final IOverlayManager mOverlayManager; - private final OneHandedTimeoutHandler mTimeoutHandler; - private final ScreenLifecycle mScreenLifecycle; - - private final ContentObserver mEnabledObserver = new ContentObserver(mMainHandler) { - @Override - public void onChange(boolean selfChange) { - final boolean enabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - mContext.getContentResolver()); - OneHandedEvents.writeEvent(enabled - ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_ON - : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_ENABLED_OFF); - if (mOneHandedController != null) { - mOneHandedController.setOneHandedEnabled(enabled); - } - - // Also checks swipe to notification settings since they all need gesture overlay. - setEnabledGesturalOverlay( - enabled || OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( - mContext.getContentResolver())); - } - }; - - private final ContentObserver mTimeoutObserver = new ContentObserver(mMainHandler) { - @Override - public void onChange(boolean selfChange) { - final int newTimeout = OneHandedSettingsUtil.getSettingsOneHandedModeTimeout( - mContext.getContentResolver()); - int metricsId = OneHandedEvents.OneHandedSettingsTogglesEvent.INVALID.getId(); - switch (newTimeout) { - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_NEVER: - metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_NEVER; - break; - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS: - metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_4; - break; - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS: - metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_8; - break; - case OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_LONG_IN_SECONDS: - metricsId = OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_TIMEOUT_SECONDS_12; - break; - default: - // do nothing - break; - } - OneHandedEvents.writeEvent(metricsId); - - if (mTimeoutHandler != null) { - mTimeoutHandler.setTimeout(newTimeout); - } - } - }; - - private final ContentObserver mTaskChangeExitObserver = new ContentObserver(mMainHandler) { - @Override - public void onChange(boolean selfChange) { - final boolean enabled = OneHandedSettingsUtil.getSettingsTapsAppToExit( - mContext.getContentResolver()); - OneHandedEvents.writeEvent(enabled - ? OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_ON - : OneHandedEvents.EVENT_ONE_HANDED_SETTINGS_APP_TAPS_EXIT_OFF); - - if (mOneHandedController != null) { - mOneHandedController.setTaskChangeToExit(enabled); - } - } - }; - - private final ContentObserver mSwipeToNotificationEnabledObserver = - new ContentObserver(mMainHandler) { - @Override - public void onChange(boolean selfChange) { - final boolean enabled = - OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( - mContext.getContentResolver()); - if (mOneHandedController != null) { - mOneHandedController.setSwipeToNotificationEnabled(enabled); - } - - // Also checks one handed mode settings since they all need gesture overlay. - setEnabledGesturalOverlay( - enabled || OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( - mContext.getContentResolver())); - } - }; - - @Inject - public OneHandedUI(Context context, - CommandQueue commandQueue, - OneHandedController oneHandedController, - ScreenLifecycle screenLifecycle) { - super(context); - - if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { - Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off"); - mCommandQueue = null; - mOneHandedController = null; - mOverlayManager = null; - mTimeoutHandler = null; - mScreenLifecycle = null; - return; - } - - mCommandQueue = commandQueue; - mOneHandedController = oneHandedController; - mTimeoutHandler = OneHandedTimeoutHandler.get(); - mScreenLifecycle = screenLifecycle; - mOverlayManager = IOverlayManager.Stub.asInterface( - ServiceManager.getService(Context.OVERLAY_SERVICE)); - } - - @Override - public void start() { - if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) { - return; - } - mCommandQueue.addCallback(this); - setupKeyguardUpdateMonitor(); - setupScreenObserver(); - setupSettingObservers(); - setupTimeoutListener(); - setupGesturalOverlay(); - updateSettings(); - } - - private void setupGesturalOverlay() { - if (!OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver())) { - return; - } - - OverlayInfo info = null; - try { - // TODO(b/157958539) migrate new RRO config file after S+ - mOverlayManager.setHighestPriority(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT); - info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY, USER_CURRENT); - } catch (RemoteException e) { /* Do nothing */ } - - if (info != null && !info.isEnabled()) { - // Enable the default gestural one handed overlay. - setEnabledGesturalOverlay(true); - } - } - - private void setupTimeoutListener() { - mTimeoutHandler.registerTimeoutListener(timeoutTime -> { - OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_TIMEOUT_OUT); - stopOneHanded(); - }); - } - - private void setupKeyguardUpdateMonitor() { - final KeyguardUpdateMonitorCallback keyguardCallback = - new KeyguardUpdateMonitorCallback() { - @Override - public void onKeyguardBouncerChanged(boolean bouncer) { - if (bouncer) { - stopOneHanded(); - } - } - - @Override - public void onKeyguardVisibilityChanged(boolean showing) { - stopOneHanded(); - } - }; - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(keyguardCallback); - } - - @Override - public void onCameraLaunchGestureDetected(int source) { - stopOneHanded(); - } - - private void setupScreenObserver() { - final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() { - @Override - public void onScreenTurningOff() { - OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT); - stopOneHanded(); - } - }; - mScreenLifecycle.addObserver(mScreenObserver); - } - - private void setupSettingObservers() { - OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED, - mContext.getContentResolver(), mEnabledObserver); - OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT, - mContext.getContentResolver(), mTimeoutObserver); - OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT, - mContext.getContentResolver(), mTaskChangeExitObserver); - OneHandedSettingsUtil.registerSettingsKeyObserver( - Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, - mContext.getContentResolver(), mSwipeToNotificationEnabledObserver); - } - - private void updateSettings() { - mOneHandedController.setOneHandedEnabled(OneHandedSettingsUtil - .getSettingsOneHandedModeEnabled(mContext.getContentResolver())); - mTimeoutHandler.setTimeout(OneHandedSettingsUtil - .getSettingsOneHandedModeTimeout(mContext.getContentResolver())); - mOneHandedController.setTaskChangeToExit(OneHandedSettingsUtil - .getSettingsTapsAppToExit(mContext.getContentResolver())); - mOneHandedController.setSwipeToNotificationEnabled(OneHandedSettingsUtil - .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver())); - } - - @Override - public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, - boolean showImeSwitcher) { - if (displayId != DEFAULT_DISPLAY) { - return; - } - if ((vis & InputMethodService.IME_VISIBLE) != 0) { - OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT); - stopOneHanded(); - } - } - - @VisibleForTesting - private void setEnabledGesturalOverlay(boolean enabled) { - try { - mOverlayManager.setEnabled(ONE_HANDED_MODE_GESTURAL_OVERLAY, enabled, USER_CURRENT); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Trigger one handed more - */ - public void startOneHanded() { - mOneHandedController.startOneHanded(); - OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_IN); - } - - /** - * Dismiss one handed more - */ - public void stopOneHanded() { - mOneHandedController.stopOneHanded(); - OneHandedEvents.writeEvent(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT); - } - - /** - * Dump all one handed data of states - */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - final String innerPrefix = " "; - pw.println(TAG + "one handed states: "); - - if (mOneHandedController != null) { - mOneHandedController.dump(fd, pw, args); - } - - if (mTimeoutHandler != null) { - mTimeoutHandler.dump(fd, pw, args); - } - - OneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver()); - - if (mOverlayManager != null) { - OverlayInfo info = null; - try { - info = mOverlayManager.getOverlayInfo(ONE_HANDED_MODE_GESTURAL_OVERLAY, - USER_CURRENT); - } catch (RemoteException e) { /* Do nothing */ } - - if (info != null && !info.isEnabled()) { - pw.print(innerPrefix + "OverlayInfo="); - pw.println(info); - } - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 56f010d7e8665..5db4e019f7f7e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -75,7 +75,8 @@ import com.android.systemui.navigationbar.NavigationBar; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.onehanded.OneHandedUI; +import com.android.systemui.onehanded.OneHanded; +import com.android.systemui.onehanded.OneHandedEvents; import com.android.systemui.pip.Pip; import com.android.systemui.pip.PipAnimationController; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; @@ -135,7 +136,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private final List mConnectionCallbacks = new ArrayList<>(); private final Intent mQuickStepIntent; private final ScreenshotHelper mScreenshotHelper; - private final OneHandedUI mOneHandedUI; + private final Optional mOneHandedOptional; private final CommandQueue mCommandQueue; private Region mActiveNavBarRegion; @@ -464,9 +465,7 @@ public class OverviewProxyService extends CurrentUserTracker implements } long token = Binder.clearCallingIdentity(); try { - if (mOneHandedUI != null) { - mOneHandedUI.startOneHanded(); - } + mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded()); } finally { Binder.restoreCallingIdentity(token); } @@ -479,9 +478,8 @@ public class OverviewProxyService extends CurrentUserTracker implements } long token = Binder.clearCallingIdentity(); try { - if (mOneHandedUI != null) { - mOneHandedUI.stopOneHanded(); - } + mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded( + OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT)); } finally { Binder.restoreCallingIdentity(token); } @@ -620,7 +618,8 @@ public class OverviewProxyService extends CurrentUserTracker implements NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, Optional pipOptional, Optional splitScreenOptional, - Optional> statusBarOptionalLazy, OneHandedUI oneHandedUI, + Optional> statusBarOptionalLazy, + Optional oneHandedOptional, BroadcastDispatcher broadcastDispatcher) { super(broadcastDispatcher); mContext = context; @@ -640,7 +639,7 @@ public class OverviewProxyService extends CurrentUserTracker implements .supportsRoundedCornersOnWindows(mContext.getResources()); mSysUiState = sysUiState; mSysUiState.addCallback(this::notifySystemUiStateFlags); - mOneHandedUI = oneHandedUI; + mOneHandedOptional = oneHandedOptional; // Assumes device always starts with back button until launcher tells it that it does not mNavBarButtonAlpha = 1.0f; diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 27af5f91c9e47..93b23e51656ff 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -16,16 +16,32 @@ package com.android.systemui.wmshell; +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; + +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE; import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import android.app.ActivityManager; +import android.content.ComponentName; import android.content.Context; +import android.graphics.Rect; +import android.inputmethodservice.InputMethodService; +import android.os.IBinder; +import android.view.KeyEvent; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.SystemUI; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.onehanded.OneHanded; +import com.android.systemui.onehanded.OneHandedEvents; +import com.android.systemui.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback; +import com.android.systemui.onehanded.OneHandedTransitionCallback; import com.android.systemui.pip.Pip; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; @@ -54,8 +70,12 @@ public final class WMShell extends SystemUI implements ProtoTraceable mPipOptional; private final Optional mSplitScreenOptional; + private final Optional mOneHandedOptional; private final ProtoTracer mProtoTracer; @Inject @@ -63,16 +83,24 @@ public final class WMShell extends SystemUI implements ProtoTraceable pipOptional, Optional splitScreenOptional, + Optional oneHandedOptional, ProtoTracer protoTracer) { super(context); mCommandQueue = commandQueue; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mActivityManagerWrapper = activityManagerWrapper; mDisplayImeController = displayImeController; + mNavigationModeController = navigationModeController; + mScreenLifecycle = screenLifecycle; + mSysUiState = sysUiState; mPipOptional = pipOptional; mSplitScreenOptional = splitScreenOptional; + mOneHandedOptional = oneHandedOptional; mProtoTracer = protoTracer; mProtoTracer.add(this); } @@ -83,9 +111,9 @@ public final class WMShell extends SystemUI implements ProtoTraceable + oneHanded.setThreeButtonModeEnabled(mode == NAV_BAR_MODE_3BUTTON)); + oneHanded.setThreeButtonModeEnabled(currentMode == NAV_BAR_MODE_3BUTTON); + + oneHanded.registerTransitionCallback(new OneHandedTransitionCallback() { + @Override + public void onStartFinished(Rect bounds) { + mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE, + true).commitUpdate(DEFAULT_DISPLAY); + } + + @Override + public void onStopFinished(Rect bounds) { + mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE, + false).commitUpdate(DEFAULT_DISPLAY); + } + }); + + oneHanded.registerGestureCallback(new OneHandedGestureEventCallback() { + @Override + public void onStart() { + if (oneHanded.isOneHandedEnabled()) { + oneHanded.startOneHanded(); + } else if (oneHanded.isSwipeToNotificationEnabled()) { + mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN); + } + } + + @Override + public void onStop() { + if (oneHanded.isOneHandedEnabled()) { + oneHanded.stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT); + } else if (oneHanded.isSwipeToNotificationEnabled()) { + mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP); + } + } + }); + + mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() { + @Override + public void onKeyguardBouncerChanged(boolean bouncer) { + if (bouncer) { + oneHanded.stopOneHanded(); + } + } + + @Override + public void onKeyguardVisibilityChanged(boolean showing) { + oneHanded.stopOneHanded(); + } + }); + + mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() { + @Override + public void onScreenTurningOff() { + oneHanded.stopOneHanded( + OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_SCREEN_OFF_OUT); + } + }); + + mCommandQueue.addCallback(new CommandQueue.Callbacks() { + @Override + public void onCameraLaunchGestureDetected(int source) { + oneHanded.stopOneHanded(); + } + + @Override + public void setImeWindowStatus(int displayId, IBinder token, int vis, + int backDisposition, boolean showImeSwitcher) { + if (displayId != DEFAULT_DISPLAY && (vis & InputMethodService.IME_VISIBLE) == 0) { + return; + } + oneHanded.stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT); + } + }); + + mActivityManagerWrapper.registerTaskStackListener( + new TaskStackChangeListener() { + @Override + public void onTaskCreated(int taskId, ComponentName componentName) { + oneHanded.stopOneHanded( + OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT); + } + + @Override + public void onTaskMovedToFront(int taskId) { + oneHanded.stopOneHanded( + OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT); + } + }); + } + @Override public void writeToProto(SystemUiTraceProto proto) { if (proto.wmShell == null) { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index e63c6c3173923..d3e5f22aa0424 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -24,6 +24,7 @@ import android.view.IWindowManager; import com.android.internal.logging.UiEventLogger; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.onehanded.OneHanded; import com.android.systemui.pip.Pip; import com.android.systemui.pip.PipSurfaceTransactionHelper; import com.android.systemui.pip.PipUiEventLogger; @@ -101,16 +102,19 @@ public abstract class WMShellBaseModule { return organizer; } - @BindsOptionalOf - abstract Pip optionalPip(); - - @BindsOptionalOf - abstract SplitScreen optionalSplitScreen(); - @SysUISingleton @Provides static FlingAnimationUtils.Builder provideFlingAnimationUtilsBuilder( DisplayMetrics displayMetrics) { return new FlingAnimationUtils.Builder(displayMetrics); } + + @BindsOptionalOf + abstract Pip optionalPip(); + + @BindsOptionalOf + abstract SplitScreen optionalSplitScreen(); + + @BindsOptionalOf + abstract OneHanded optionalOneHanded(); } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 1870b7605567c..3050aefb97d22 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -24,6 +24,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.model.SysUiState; +import com.android.systemui.onehanded.OneHanded; +import com.android.systemui.onehanded.OneHandedController; import com.android.systemui.pip.Pip; import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.pip.PipSurfaceTransactionHelper; @@ -109,4 +111,10 @@ public class WMShellModule { pipUiEventLogger, shellTaskOrganizer); } + @SysUISingleton + @Provides + static OneHanded provideOneHandedController(Context context, + DisplayController displayController) { + return OneHandedController.create(context, displayController); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java index 02d587d90655c..e42cf529373ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedControllerTest.java @@ -22,21 +22,20 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.Display; import androidx.test.filters.SmallTest; -import com.android.systemui.model.SysUiState; -import com.android.systemui.statusbar.CommandQueue; import com.android.wm.shell.common.DisplayController; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -51,8 +50,6 @@ public class OneHandedControllerTest extends OneHandedTestCase { OneHandedController mOneHandedController; OneHandedTimeoutHandler mTimeoutHandler; - @Mock - CommandQueue mCommandQueue; @Mock DisplayController mMockDisplayController; @Mock @@ -64,21 +61,20 @@ public class OneHandedControllerTest extends OneHandedTestCase { @Mock OneHandedGestureHandler mMockGestureHandler; @Mock - SysUiState mMockSysUiState; + OneHandedTimeoutHandler mMockTimeoutHandler; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mDisplay = mContext.getDisplay(); - mOneHandedController = new OneHandedController( - getContext(), - mCommandQueue, + OneHandedController oneHandedController = new OneHandedController( + mContext, mMockDisplayController, mMockDisplayAreaOrganizer, mMockTouchHandler, mMockTutorialHandler, - mMockGestureHandler, - mMockSysUiState); + mMockGestureHandler); + mOneHandedController = Mockito.spy(oneHandedController); mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get()); when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay); @@ -97,7 +93,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { @Test public void testRegisterOrganizer() { - verify(mMockDisplayAreaOrganizer).registerOrganizer(anyInt()); + verify(mMockDisplayAreaOrganizer, atLeastOnce()).registerOrganizer(anyInt()); } @Test @@ -132,7 +128,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { final boolean enabled = true; mOneHandedController.setOneHandedEnabled(enabled); - verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled); + verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(enabled); } @Test @@ -140,6 +136,44 @@ public class OneHandedControllerTest extends OneHandedTestCase { final boolean enabled = true; mOneHandedController.setSwipeToNotificationEnabled(enabled); - verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled); + verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(enabled); + } + + @Ignore("b/161980408, fix it after migration finished") + @Test + public void tesSettingsObserver_updateTapAppToExit() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.TAPS_APP_TO_EXIT, 1); + + verify(mOneHandedController).setTaskChangeToExit(true); + } + + @Ignore("b/161980408, fix it after migration finished") + @Test + public void tesSettingsObserver_updateEnabled() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ONE_HANDED_MODE_ENABLED, 1); + + verify(mOneHandedController).setOneHandedEnabled(true); + } + + @Ignore("b/161980408, fix it after migration finished") + @Test + public void tesSettingsObserver_updateTimeout() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ONE_HANDED_MODE_TIMEOUT, + OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); + + verify(mMockTimeoutHandler).setTimeout( + OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); + } + + @Ignore("b/161980408, fix it after migration finished") + @Test + public void tesSettingsObserver_updateSwipeToNotification() { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1); + + verify(mOneHandedController).setSwipeToNotificationEnabled(true); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java index 756382a6c6300..41af53b1c5226 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java @@ -16,12 +16,10 @@ package com.android.systemui.onehanded; -import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; - import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.verify; import android.testing.AndroidTestingRunner; @@ -29,9 +27,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.systemui.model.SysUiState; -import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.statusbar.CommandQueue; import com.android.wm.shell.common.DisplayController; import org.junit.Before; @@ -50,52 +45,55 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { OneHandedGestureHandler mGestureHandler; OneHandedController mOneHandedController; @Mock - CommandQueue mCommandQueue; - @Mock DisplayController mMockDisplayController; @Mock OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer; - @Mock - SysUiState mMockSysUiState; - @Mock - NavigationModeController mMockNavigationModeController; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mTouchHandler = new OneHandedTouchHandler(); mTutorialHandler = new OneHandedTutorialHandler(mContext); - mGestureHandler = Mockito.spy(new OneHandedGestureHandler( - mContext, mMockDisplayController, mMockNavigationModeController)); + mGestureHandler = Mockito.spy( + new OneHandedGestureHandler(mContext, mMockDisplayController)); mOneHandedController = new OneHandedController( getContext(), - mCommandQueue, mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, mTutorialHandler, - mGestureHandler, - mMockSysUiState); + mGestureHandler); + mOneHandedController.setThreeButtonModeEnabled(true); } @Test public void testOneHandedManager_registerForDisplayAreaOrganizer() { - verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mGestureHandler); + verify(mMockDisplayAreaOrganizer, atLeastOnce()) + .registerTransitionCallback(mGestureHandler); } @Test public void testOneHandedManager_setGestureEventListener() { - verify(mGestureHandler).setGestureEventListener(any()); + OneHandedGestureHandler.OneHandedGestureEventCallback callback = + new OneHandedGestureHandler.OneHandedGestureEventCallback() { + @Override + public void onStart() {} - assertThat(mGestureHandler.mGestureEventCallback).isNotNull(); + @Override + public void onStop() {} + }; + mOneHandedController.registerGestureCallback(callback); + + verify(mGestureHandler).setGestureEventListener(callback); + assertThat(mGestureHandler.mGestureEventCallback).isEqualTo(callback); } @Test public void testReceiveNewConfig_whenSetOneHandedEnabled() { // 1st called at init - verify(mGestureHandler).onOneHandedEnabled(true); + verify(mGestureHandler, atLeastOnce()).onOneHandedEnabled(true); mOneHandedController.setOneHandedEnabled(true); // 2nd called by setOneHandedEnabled() - verify(mGestureHandler, times(2)).onOneHandedEnabled(true); + verify(mGestureHandler, atLeast(2)).onOneHandedEnabled(true); } @Test @@ -108,14 +106,14 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { } @Test - public void testChangeNavBarTo2Button_shouldDisposeInputChannel() { + public void testChangeNavBarToNon3Button_shouldDisposeInputChannel() { // 1st called at init - verify(mGestureHandler).onOneHandedEnabled(true); + verify(mGestureHandler, atLeastOnce()).onOneHandedEnabled(true); mOneHandedController.setOneHandedEnabled(true); // 2nd called by setOneHandedEnabled() - verify(mGestureHandler, times(2)).onOneHandedEnabled(true); + verify(mGestureHandler, atLeast(2)).onOneHandedEnabled(true); - mGestureHandler.onNavigationModeChanged(NAV_BAR_MODE_2BUTTON); + mGestureHandler.onThreeButtonModeEnabled(false); assertThat(mGestureHandler.mInputMonitor).isNull(); assertThat(mGestureHandler.mInputEventReceiver).isNull(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java index 04ebf25e1b490..f111c48964581 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java @@ -16,8 +16,12 @@ package com.android.systemui.onehanded; +import static com.android.systemui.onehanded.OneHandedController.SUPPORT_ONE_HANDED_MODE; import static com.android.systemui.onehanded.OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS; +import static org.junit.Assume.assumeTrue; + +import android.os.SystemProperties; import android.provider.Settings; import com.android.systemui.SysuiTestCase; @@ -54,6 +58,11 @@ public abstract class OneHandedTestCase extends SysuiTestCase { Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1); } + @Before + public void assumeOneHandedModeSupported() { + assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)); + } + @After public void restoreSettings() { Settings.Secure.putInt(getContext().getContentResolver(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java index 3c3ace052e47c..1e408313a36ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java @@ -19,7 +19,8 @@ package com.android.systemui.onehanded; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.verify; import android.testing.AndroidTestingRunner; @@ -27,9 +28,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.systemui.model.SysUiState; -import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.statusbar.CommandQueue; import com.android.wm.shell.common.DisplayController; import org.junit.Before; @@ -48,31 +46,22 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase { OneHandedGestureHandler mGestureHandler; OneHandedController mOneHandedController; @Mock - CommandQueue mCommandQueue; - @Mock DisplayController mMockDisplayController; @Mock - NavigationModeController mMockNavigationModeController; - @Mock OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer; - @Mock - SysUiState mMockSysUiState; @Before public void setUp() { MockitoAnnotations.initMocks(this); mTouchHandler = Mockito.spy(new OneHandedTouchHandler()); - mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController, - mMockNavigationModeController); + mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController); mOneHandedController = new OneHandedController( getContext(), - mCommandQueue, mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, mTutorialHandler, - mGestureHandler, - mMockSysUiState); + mGestureHandler); } @Test @@ -102,10 +91,10 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase { @Test public void testReceiveNewConfig_whenSetOneHandedEnabled() { - // 1st called at init - verify(mTouchHandler).onOneHandedEnabled(true); + // Called at init + verify(mTouchHandler, atLeastOnce()).onOneHandedEnabled(true); mOneHandedController.setOneHandedEnabled(true); - // 2nd called by setOneHandedEnabled() - verify(mTouchHandler, times(2)).onOneHandedEnabled(true); + // Called by setOneHandedEnabled() + verify(mTouchHandler, atLeast(2)).onOneHandedEnabled(true); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java index 1bffbf7eb8dd1..8ea5524eb7e62 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java @@ -23,9 +23,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.systemui.model.SysUiState; -import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.statusbar.CommandQueue; import com.android.wm.shell.common.DisplayController; import org.junit.Before; @@ -44,32 +41,23 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { OneHandedGestureHandler mGestureHandler; OneHandedController mOneHandedController; @Mock - CommandQueue mCommandQueue; - @Mock DisplayController mMockDisplayController; @Mock - NavigationModeController mMockNavigationModeController; - @Mock OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer; - @Mock - SysUiState mMockSysUiState; @Before public void setUp() { MockitoAnnotations.initMocks(this); mTouchHandler = new OneHandedTouchHandler(); mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext)); - mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController, - mMockNavigationModeController); + mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController); mOneHandedController = new OneHandedController( getContext(), - mCommandQueue, mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, mTutorialHandler, - mGestureHandler, - mMockSysUiState); + mGestureHandler); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java deleted file mode 100644 index ae3df5db30bcc..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.onehanded; - -import static org.junit.Assume.assumeTrue; -import static org.mockito.Mockito.verify; - -import android.os.SystemProperties; -import android.provider.Settings; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import androidx.test.filters.SmallTest; - -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.statusbar.CommandQueue; - -import org.junit.Before; -import org.junit.Ignore; -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 OneHandedUITest extends OneHandedTestCase { - private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; - - CommandQueue mCommandQueue; - KeyguardUpdateMonitor mKeyguardUpdateMonitor; - OneHandedUI mOneHandedUI; - ScreenLifecycle mScreenLifecycle; - @Mock - OneHandedController mOneHandedController; - @Mock - OneHandedTimeoutHandler mMockTimeoutHandler; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mCommandQueue = new CommandQueue(mContext); - mScreenLifecycle = new ScreenLifecycle(); - mOneHandedUI = new OneHandedUI(mContext, - mCommandQueue, - mOneHandedController, - mScreenLifecycle); - mOneHandedUI.start(); - mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class); - } - - @Before - public void assumeOneHandedModeSupported() { - assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)); - } - - @Test - public void testStartOneHanded() { - mOneHandedUI.startOneHanded(); - - verify(mOneHandedController).startOneHanded(); - } - - @Test - public void testStopOneHanded() { - mOneHandedUI.stopOneHanded(); - - verify(mOneHandedController).stopOneHanded(); - } - - @Test - public void tesSettingsObserver_updateTapAppToExit() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.TAPS_APP_TO_EXIT, 1); - - verify(mOneHandedController).setTaskChangeToExit(true); - } - - @Test - public void tesSettingsObserver_updateEnabled() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ONE_HANDED_MODE_ENABLED, 1); - - verify(mOneHandedController).setOneHandedEnabled(true); - } - - @Test - public void tesSettingsObserver_updateTimeout() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.ONE_HANDED_MODE_TIMEOUT, - OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); - - verify(mMockTimeoutHandler).setTimeout( - OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); - } - - @Test - public void tesSettingsObserver_updateSwipeToNotification() { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1); - - verify(mOneHandedController).setSwipeToNotificationEnabled(true); - } - - @Ignore("Clarifying do not receive callback") - @Test - public void testKeyguardBouncerShowing_shouldStopOneHanded() { - mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true); - - verify(mOneHandedController).stopOneHanded(); - } - - @Test - public void testScreenTurningOff_shouldStopOneHanded() { - mScreenLifecycle.dispatchScreenTurningOff(); - - verify(mOneHandedController).stopOneHanded(); - } - -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java index ac9346f675be7..79da45a86f351 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java @@ -18,6 +18,7 @@ package com.android.systemui.wmshell; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.test.suitebuilder.annotation.SmallTest; @@ -26,6 +27,12 @@ import androidx.test.runner.AndroidJUnit4; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.SysuiTestCase; +import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.NavigationModeController; +import com.android.systemui.onehanded.OneHanded; +import com.android.systemui.onehanded.OneHandedGestureHandler; +import com.android.systemui.onehanded.OneHandedTransitionCallback; import com.android.systemui.pip.Pip; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; @@ -51,16 +58,21 @@ public class WMShellTest extends SysuiTestCase { @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock ActivityManagerWrapper mActivityManagerWrapper; @Mock DisplayImeController mDisplayImeController; + @Mock NavigationModeController mNavigationModeController; + @Mock ScreenLifecycle mScreenLifecycle; + @Mock SysUiState mSysUiState; @Mock Pip mPip; @Mock SplitScreen mSplitScreen; + @Mock OneHanded mOneHanded; @Mock ProtoTracer mProtoTracer; @Before public void setUp() { MockitoAnnotations.initMocks(this); mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor, - mActivityManagerWrapper, mDisplayImeController, Optional.of(mPip), - Optional.of(mSplitScreen), mProtoTracer); + mActivityManagerWrapper, mDisplayImeController, mNavigationModeController, + mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen), + Optional.of(mOneHanded), mProtoTracer); } @Test @@ -85,4 +97,22 @@ public class WMShellTest extends SysuiTestCase { verify(mActivityManagerWrapper).registerTaskStackListener( any(TaskStackChangeListener.class)); } + + @Test + public void initOneHanded_registersCallbacks() { + when(mOneHanded.hasOneHandedFeature()).thenReturn(true); + mWMShell.initOneHanded(mOneHanded); + + verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class)); + verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class)); + verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class)); + verify(mNavigationModeController).addListener( + any(NavigationModeController.ModeChangedListener.class)); + verify(mActivityManagerWrapper).registerTaskStackListener( + any(TaskStackChangeListener.class)); + + verify(mOneHanded).registerGestureCallback(any( + OneHandedGestureHandler.OneHandedGestureEventCallback.class)); + verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class)); + } }