Add task unpinning support for 3 button taskbar
Bug: 199544447 Test: Tested on small and large screen Change-Id: Ib7785992ef11825cd07a929e2cb623d02ef246f1
This commit is contained in:
parent
b78cbf29e5
commit
570653346f
|
@ -31,6 +31,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_I
|
|||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
|
||||
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ObjectAnimator;
|
||||
|
@ -86,6 +87,7 @@ public class NavbarButtonsViewController {
|
|||
private static final int FLAG_DISABLE_RECENTS = 1 << 8;
|
||||
private static final int FLAG_DISABLE_BACK = 1 << 9;
|
||||
private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10;
|
||||
private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 10;
|
||||
|
||||
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
|
||||
|
||||
|
@ -152,7 +154,9 @@ public class NavbarButtonsViewController {
|
|||
mPropertyHolders.add(new StatePropertyHolder(
|
||||
mControllers.taskbarViewController.getTaskbarIconAlpha()
|
||||
.getProperty(ALPHA_INDEX_KEYGUARD),
|
||||
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
|
||||
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
|
||||
&& (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0,
|
||||
MultiValueAlpha.VALUE, 1, 0));
|
||||
|
||||
mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
|
||||
.getKeyguardBgTaskbar(),
|
||||
|
@ -286,6 +290,7 @@ public class NavbarButtonsViewController {
|
|||
int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
|
||||
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
|
||||
boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0;
|
||||
boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
|
||||
|
||||
// TODO(b/202218289) we're getting IME as not visible on lockscreen from system
|
||||
updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
|
||||
|
@ -295,6 +300,7 @@ public class NavbarButtonsViewController {
|
|||
updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled);
|
||||
updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled);
|
||||
updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded);
|
||||
updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive);
|
||||
|
||||
if (mA11yButton != null) {
|
||||
// Only used in 3 button
|
||||
|
|
|
@ -361,6 +361,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
|
|||
mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
|
||||
mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
|
||||
fromInit);
|
||||
mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,8 +29,8 @@ import android.content.pm.ActivityInfo;
|
|||
import android.content.res.Configuration;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -93,7 +93,8 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
|||
Display display =
|
||||
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
|
||||
mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
|
||||
mNavButtonController = new TaskbarNavButtonController(service);
|
||||
mNavButtonController = new TaskbarNavButtonController(service,
|
||||
SystemUiProxy.INSTANCE.get(mContext), new Handler());
|
||||
mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
|
||||
mComponentCallbacks = new ComponentCallbacks() {
|
||||
private Configuration mOldConfig = mContext.getResources().getConfiguration();
|
||||
|
|
|
@ -19,8 +19,10 @@ package com.android.launcher3.taskbar;
|
|||
|
||||
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
|
||||
import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
|
@ -40,6 +42,13 @@ import java.lang.annotation.RetentionPolicy;
|
|||
*/
|
||||
public class TaskbarNavButtonController {
|
||||
|
||||
/** Allow some time in between the long press for back and recents. */
|
||||
static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200;
|
||||
static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100;
|
||||
|
||||
private long mLastScreenPinLongPress;
|
||||
private boolean mScreenPinned;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
BUTTON_BACK,
|
||||
|
@ -57,10 +66,20 @@ public class TaskbarNavButtonController {
|
|||
static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1;
|
||||
static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1;
|
||||
|
||||
private final TouchInteractionService mService;
|
||||
private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS;
|
||||
private int mLongPressedButtons = 0;
|
||||
|
||||
public TaskbarNavButtonController(TouchInteractionService service) {
|
||||
private final TouchInteractionService mService;
|
||||
private final SystemUiProxy mSystemUiProxy;
|
||||
private final Handler mHandler;
|
||||
|
||||
private final Runnable mResetLongPress = this::resetScreenUnpin;
|
||||
|
||||
public TaskbarNavButtonController(TouchInteractionService service,
|
||||
SystemUiProxy systemUiProxy, Handler handler) {
|
||||
mService = service;
|
||||
mSystemUiProxy = systemUiProxy;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
public void onButtonClick(@TaskbarButton int buttonType) {
|
||||
|
@ -72,13 +91,13 @@ public class TaskbarNavButtonController {
|
|||
navigateHome();
|
||||
break;
|
||||
case BUTTON_RECENTS:
|
||||
navigateToOverview();;
|
||||
navigateToOverview();
|
||||
break;
|
||||
case BUTTON_IME_SWITCH:
|
||||
showIMESwitcher();
|
||||
break;
|
||||
case BUTTON_A11Y:
|
||||
notifyImeClick(false /* longClick */);
|
||||
notifyA11yClick(false /* longClick */);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -89,46 +108,98 @@ public class TaskbarNavButtonController {
|
|||
startAssistant();
|
||||
return true;
|
||||
case BUTTON_A11Y:
|
||||
notifyImeClick(true /* longClick */);
|
||||
notifyA11yClick(true /* longClick */);
|
||||
return true;
|
||||
case BUTTON_BACK:
|
||||
case BUTTON_IME_SWITCH:
|
||||
case BUTTON_RECENTS:
|
||||
mLongPressedButtons |= buttonType;
|
||||
return determineScreenUnpin();
|
||||
case BUTTON_IME_SWITCH:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user has long pressed back and recents buttons
|
||||
* "together" (within {@link #SCREEN_PIN_LONG_PRESS_THRESHOLD})ms
|
||||
* If so, then requests the system to turn off screen pinning.
|
||||
*
|
||||
* @return true if the long press is a valid user action in attempting to unpin an app
|
||||
* Will always return {@code false} when screen pinning is not active.
|
||||
* NOTE: Returning true does not mean that screen pinning has stopped
|
||||
*/
|
||||
private boolean determineScreenUnpin() {
|
||||
long timeNow = System.currentTimeMillis();
|
||||
if (!mScreenPinned) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mLastScreenPinLongPress == 0) {
|
||||
// First button long press registered, just mark time and wait for second button press
|
||||
mLastScreenPinLongPress = System.currentTimeMillis();
|
||||
mHandler.postDelayed(mResetLongPress, SCREEN_PIN_LONG_PRESS_RESET);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((timeNow - mLastScreenPinLongPress) > SCREEN_PIN_LONG_PRESS_THRESHOLD) {
|
||||
// Too long in-between presses, reset the clock
|
||||
resetScreenUnpin();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((mLongPressedButtons & SCREEN_UNPIN_COMBO) == SCREEN_UNPIN_COMBO) {
|
||||
// Hooray! They did it (finally...)
|
||||
mSystemUiProxy.stopScreenPinning();
|
||||
mHandler.removeCallbacks(mResetLongPress);
|
||||
resetScreenUnpin();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void resetScreenUnpin() {
|
||||
mLongPressedButtons = 0;
|
||||
mLastScreenPinLongPress = 0;
|
||||
}
|
||||
|
||||
public void updateSysuiFlags(int sysuiFlags) {
|
||||
mScreenPinned = (sysuiFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
|
||||
}
|
||||
|
||||
private void navigateHome() {
|
||||
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
|
||||
}
|
||||
|
||||
private void navigateToOverview() {
|
||||
if (mScreenPinned) {
|
||||
return;
|
||||
}
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
|
||||
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE);
|
||||
}
|
||||
|
||||
private void executeBack() {
|
||||
SystemUiProxy.INSTANCE.getNoCreate().onBackPressed();
|
||||
mSystemUiProxy.onBackPressed();
|
||||
}
|
||||
|
||||
private void showIMESwitcher() {
|
||||
SystemUiProxy.INSTANCE.getNoCreate().onImeSwitcherPressed();
|
||||
mSystemUiProxy.onImeSwitcherPressed();
|
||||
}
|
||||
|
||||
private void notifyImeClick(boolean longClick) {
|
||||
SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
|
||||
private void notifyA11yClick(boolean longClick) {
|
||||
if (longClick) {
|
||||
systemUiProxy.notifyAccessibilityButtonLongClicked();
|
||||
mSystemUiProxy.notifyAccessibilityButtonLongClicked();
|
||||
} else {
|
||||
systemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
|
||||
mSystemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
|
||||
}
|
||||
}
|
||||
|
||||
private void startAssistant() {
|
||||
if (mScreenPinned) {
|
||||
return;
|
||||
}
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
|
||||
SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
|
||||
systemUiProxy.startAssistant(args);
|
||||
mSystemUiProxy.startAssistant(args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
|
||||
import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
|
||||
import static com.android.quickstep.OverviewCommandHelper.TYPE_HOME;
|
||||
import static com.android.quickstep.OverviewCommandHelper.TYPE_TOGGLE;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.Handler;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.quickstep.OverviewCommandHelper;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TouchInteractionService;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaskbarNavButtonControllerTest {
|
||||
|
||||
private final static int DISPLAY_ID = 2;
|
||||
|
||||
@Mock
|
||||
SystemUiProxy mockSystemUiProxy;
|
||||
@Mock
|
||||
TouchInteractionService mockService;
|
||||
@Mock
|
||||
OverviewCommandHelper mockCommandHelper;
|
||||
@Mock
|
||||
Handler mockHandler;
|
||||
|
||||
private TaskbarNavButtonController mNavButtonController;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
|
||||
when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
|
||||
mNavButtonController = new TaskbarNavButtonController(mockService,
|
||||
mockSystemUiProxy, mockHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressBack() {
|
||||
mNavButtonController.onButtonClick(BUTTON_BACK);
|
||||
verify(mockSystemUiProxy, times(1)).onBackPressed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressImeSwitcher() {
|
||||
mNavButtonController.onButtonClick(BUTTON_IME_SWITCH);
|
||||
verify(mockSystemUiProxy, times(1)).onImeSwitcherPressed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressA11yShortClick() {
|
||||
mNavButtonController.onButtonClick(BUTTON_A11Y);
|
||||
verify(mockSystemUiProxy, times(1))
|
||||
.notifyAccessibilityButtonClicked(DISPLAY_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressA11yLongClick() {
|
||||
mNavButtonController.onButtonLongClick(BUTTON_A11Y);
|
||||
verify(mockSystemUiProxy, times(1)).notifyAccessibilityButtonLongClicked();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressHome() {
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME);
|
||||
verify(mockSystemUiProxy, times(1)).startAssistant(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressHome() {
|
||||
mNavButtonController.onButtonClick(BUTTON_HOME);
|
||||
verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressRecents() {
|
||||
mNavButtonController.onButtonClick(BUTTON_RECENTS);
|
||||
verify(mockCommandHelper, times(1)).addCommand(TYPE_TOGGLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPressRecentsWithScreenPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonClick(BUTTON_RECENTS);
|
||||
verify(mockCommandHelper, times(0)).addCommand(TYPE_TOGGLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsNotPinned() {
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK);
|
||||
verify(mockSystemUiProxy, times(0)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK);
|
||||
verify(mockSystemUiProxy, times(1)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsTooLongPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
|
||||
try {
|
||||
Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK);
|
||||
verify(mockSystemUiProxy, times(0)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressBackRecentsMultipleAttemptPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
|
||||
try {
|
||||
Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK);
|
||||
verify(mockSystemUiProxy, times(0)).stopScreenPinning();
|
||||
|
||||
// Try again w/in threshold
|
||||
mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_BACK);
|
||||
verify(mockSystemUiProxy, times(1)).stopScreenPinning();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPressHomeScreenPinned() {
|
||||
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
|
||||
mNavButtonController.onButtonLongClick(BUTTON_HOME);
|
||||
verify(mockSystemUiProxy, times(0)).startAssistant(any());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue