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:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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=");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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=");
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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=");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user