Migrate OneHanded to WM shell (3/n)

Remove OneHnadedUI and use OneHandedController through WMShell.

Bug: 161980408
Test: m
Test: atest com.android.systemui.onehanded
Test: manual check OneHanded funcation
Change-Id: I5148a9a74799ecd911f23403ca2d5df487717fc9
This commit is contained in:
Tony Huang
2020-08-21 17:29:13 +08:00
parent 59de240954
commit 29cefc7757
24 changed files with 654 additions and 792 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -39,7 +39,6 @@
<item>com.android.systemui.SizeCompatModeActivityController</item>
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.toast.ToastUI</item>
<item>com.android.systemui.onehanded.OneHandedUI</item>
<item>com.android.systemui.wmshell.WMShell</item>
</string-array>

View File

@@ -320,7 +320,6 @@
<item>com.android.systemui.accessibility.WindowMagnification</item>
<item>com.android.systemui.accessibility.SystemActions</item>
<item>com.android.systemui.toast.ToastUI</item>
<item>com.android.systemui.onehanded.OneHandedUI</item>
<item>com.android.systemui.wmshell.WMShell</item>
</string-array>

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}
}
}
}

View File

@@ -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=");

View File

@@ -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) {

View File

@@ -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=");

View File

@@ -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.
*/

View File

@@ -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=");

View File

@@ -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);
}
}
}
}

View File

@@ -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<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
private final ScreenshotHelper mScreenshotHelper;
private final OneHandedUI mOneHandedUI;
private final Optional<OneHanded> 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<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<Lazy<StatusBar>> statusBarOptionalLazy, OneHandedUI oneHandedUI,
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> 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;

View File

@@ -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<SystemUiTr
private final DisplayImeController mDisplayImeController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ActivityManagerWrapper mActivityManagerWrapper;
private final NavigationModeController mNavigationModeController;
private final ScreenLifecycle mScreenLifecycle;
private final SysUiState mSysUiState;
private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<OneHanded> mOneHandedOptional;
private final ProtoTracer mProtoTracer;
@Inject
@@ -63,16 +83,24 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
KeyguardUpdateMonitor keyguardUpdateMonitor,
ActivityManagerWrapper activityManagerWrapper,
DisplayImeController displayImeController,
NavigationModeController navigationModeController,
ScreenLifecycle screenLifecycle,
SysUiState sysUiState,
Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<OneHanded> 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<SystemUiTr
// constructor. And make sure the initialization of DisplayImeController won't depend on
// specific feature anymore.
mDisplayImeController.startMonitorDisplays();
mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
mOneHandedOptional.ifPresent(this::initOneHanded);
}
@VisibleForTesting
@@ -145,6 +173,104 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
});
}
@VisibleForTesting
void initOneHanded(OneHanded oneHanded) {
if (!oneHanded.hasOneHandedFeature()) {
return;
}
int currentMode = mNavigationModeController.addListener(mode ->
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) {

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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(),

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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));
}
}