summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java186
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java47
3 files changed, 235 insertions, 4 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 6fd3bb2c8222..4462c7218a76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -26,6 +26,7 @@ import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
@@ -56,6 +57,8 @@ import android.content.IntentFilter;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
@@ -71,6 +74,7 @@ import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
+import android.view.Gravity;
import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -104,6 +108,7 @@ import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.CommandQueue;
@@ -133,7 +138,7 @@ import dagger.Lazy;
* on clicks and view states of the nav bar.
*/
public class NavigationBarFragment extends LifecycleFragment implements Callbacks,
- NavigationModeController.ModeChangedListener {
+ NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener {
public static final String TAG = "NavigationBar";
private static final boolean DEBUG = false;
@@ -141,6 +146,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
private static final String EXTRA_APPEARANCE = "appearance";
private static final String EXTRA_TRANSIENT_STATE = "transient_state";
+ private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
+
/** Allow some time inbetween the long press for back and recents. */
private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
@@ -199,6 +206,23 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private boolean mIsOnDefaultDisplay;
public boolean mHomeBlockedThisTouch;
+ /**
+ * When user is QuickSwitching between apps of different orientations, we'll draw a fake
+ * home handle on the orientation they originally touched down to start their swipe
+ * gesture to indicate to them that they can continue in that orientation without having to
+ * rotate the phone
+ * The secondary handle will show when we get
+ * {@link OverviewProxyListener#onQuickSwitchToNewTask(int)} callback with the
+ * original handle hidden and we'll flip the visibilities once the
+ * {@link #mTasksFrozenListener} fires
+ */
+ private NavigationHandle mOrientationHandle;
+ private WindowManager.LayoutParams mOrientationParams;
+ private boolean mFrozenTasks;
+ private int mStartingQuickSwitchRotation;
+ private int mCurrentRotation;
+ private boolean mFixedRotationEnabled;
+
/** Only for default display */
@Nullable
private AssistHandleViewController mAssistHandlerViewController;
@@ -249,6 +273,12 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
@Override
+ public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
+ mStartingQuickSwitchRotation = rotation;
+ orientSecondaryHomeHandle();
+ }
+
+ @Override
public void startAssistant(Bundle bundle) {
mAssistManager.startAssist(bundle);
}
@@ -271,6 +301,22 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
};
+ private TaskStackChangeListener mTasksFrozenListener = new TaskStackChangeListener() {
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ mFrozenTasks = frozen;
+ orientSecondaryHomeHandle();
+ }
+ };
+
+ private NavigationBarTransitions.DarkIntensityListener mOrientationHandleIntensityListener =
+ new NavigationBarTransitions.DarkIntensityListener() {
+ @Override
+ public void onDarkIntensity(float darkIntensity) {
+ mOrientationHandle.setDarkIntensity(darkIntensity);
+ }
+ };
+
private final ContextButtonListener mRotationButtonListener = (button, visible) -> {
if (visible) {
// If the button will actually become visible and the navbar is about to hide,
@@ -294,6 +340,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
};
+ private final ContentObserver mFixedRotationObserver = new ContentObserver(
+ new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updatedFixedRotation();
+ }
+ };
+
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
new DeviceConfig.OnPropertiesChangedListener() {
@Override
@@ -351,6 +405,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(FIXED_ROTATION_TRANSFORM_SETTING_NAME),
+ false /* notifyForDescendants */, mFixedRotationObserver, UserHandle.USER_ALL);
+
if (savedInstanceState != null) {
mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
@@ -376,6 +434,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
mNavigationModeController.removeListener(this);
mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
mContentResolver.unregisterContentObserver(mAssistContentObserver);
+ mContentResolver.unregisterContentObserver(mFixedRotationObserver);
DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
}
@@ -406,6 +465,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
+ updatedFixedRotation();
prepareNavigationBarView();
checkNavBarModes();
@@ -442,6 +502,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
new AssistHandleViewController(mHandler, mNavigationBarView);
getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController);
}
+
+ initSecondaryHomeHandleForRotation();
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mTasksFrozenListener);
}
@Override
@@ -458,6 +521,13 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
mOverviewProxyService.removeCallback(mOverviewProxyListener);
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTasksFrozenListener);
+ if (mOrientationHandle != null) {
+ resetSecondaryHandle();
+ getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this);
+ getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
+ mWindowManager.removeView(mOrientationHandle);
+ }
}
@Override
@@ -490,6 +560,88 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
repositionNavigationBar();
}
+ private void initSecondaryHomeHandleForRotation() {
+ if (!canShowSecondaryHandle()) {
+ return;
+ }
+
+ getContext().getSystemService(DisplayManager.class)
+ .registerDisplayListener(this, new Handler(Looper.getMainLooper()));
+
+ mOrientationHandle = new VerticalNavigationHandle(getContext());
+
+ getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener);
+ mOrientationParams = new WindowManager.LayoutParams(0, 0,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_SLIPPERY,
+ PixelFormat.TRANSLUCENT);
+ mWindowManager.addView(mOrientationHandle, mOrientationParams);
+ mOrientationHandle.setVisibility(View.GONE);
+ }
+
+ private void orientSecondaryHomeHandle() {
+ if (!canShowSecondaryHandle()) {
+ return;
+ }
+
+ if (!mFrozenTasks) {
+ resetSecondaryHandle();
+ } else {
+ int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation);
+ int height = 0;
+ int width = 0;
+ Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
+ switch (deltaRotation) {
+ case Surface.ROTATION_90:
+ case Surface.ROTATION_270:
+ height = dispSize.height();
+ width = getResources()
+ .getDimensionPixelSize(R.dimen.navigation_bar_height);
+ break;
+ case Surface.ROTATION_180:
+ case Surface.ROTATION_0:
+ // TODO(b/152683657): Need to determine best UX for this
+ resetSecondaryHandle();
+ return;
+ }
+
+ mOrientationParams.gravity =
+ deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT;
+ mOrientationParams.height = height;
+ mOrientationParams.width = width;
+ mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams);
+ mNavigationBarView.setVisibility(View.GONE);
+ mOrientationHandle.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void resetSecondaryHandle() {
+ if (mOrientationHandle != null) {
+ // Case where nav mode is changed w/o ever invoking a quickstep
+ // mOrientedHandle is initialized lazily
+ mOrientationHandle.setVisibility(View.GONE);
+ }
+ mNavigationBarView.setVisibility(View.VISIBLE);
+ }
+
+ private int deltaRotation(int oldRotation, int newRotation) {
+ int delta = newRotation - oldRotation;
+ if (delta < 0) delta += 4;
+ return delta;
+ }
+
+ private void updatedFixedRotation() {
+ mFixedRotationEnabled = Settings.Global.getInt(getContext().getContentResolver(),
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
+ if (!canShowSecondaryHandle()) {
+ resetSecondaryHandle();
+ }
+ }
+
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
if (mNavigationBarView != null) {
@@ -1112,6 +1264,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
mNavBarMode = mode;
updateScreenPinningGestures();
+ if (!canShowSecondaryHandle()) {
+ resetSecondaryHandle();
+ }
+
// Workaround for b/132825155, for secondary users, we currently don't receive configuration
// changes on overlay package change since SystemUI runs for the system user. In this case,
// trigger a new configuration change to ensure that the nav bar is updated in the same way.
@@ -1156,6 +1312,34 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private final AccessibilityServicesStateChangeListener mAccessibilityListener =
this::updateAccessibilityServicesState;
+ @Override
+ public void onDisplayAdded(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (!canShowSecondaryHandle()) {
+ return;
+ }
+
+ int rotation = getContext().getResources().getConfiguration()
+ .windowConfiguration.getRotation();
+ if (rotation != mCurrentRotation) {
+ mCurrentRotation = rotation;
+ orientSecondaryHomeHandle();
+ }
+ }
+
+ private boolean canShowSecondaryHandle() {
+ return mFixedRotationEnabled && mNavBarMode == NAV_BAR_MODE_GESTURAL;
+ }
+
private final Consumer<Integer> mRotationWatcher = rotation -> {
if (mNavigationBarView != null
&& mNavigationBarView.needsReorient(rotation)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
index abceb11b36e9..b87479505d00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
@@ -32,11 +32,11 @@ import com.android.systemui.R;
public class NavigationHandle extends View implements ButtonInterface {
- private final Paint mPaint = new Paint();
+ protected final Paint mPaint = new Paint();
private @ColorInt final int mLightColor;
private @ColorInt final int mDarkColor;
- private final int mRadius;
- private final int mBottom;
+ protected final int mRadius;
+ protected final int mBottom;
private boolean mRequiresInvalidate;
public NavigationHandle(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
new file mode 100644
index 000000000000..a15ca9532a88
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Canvas;
+
+import com.android.systemui.R;
+
+/** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
+public class VerticalNavigationHandle extends NavigationHandle {
+ private final int mWidth;
+
+ public VerticalNavigationHandle(Context context) {
+ super(context);
+ mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int left;
+ int top;
+ int bottom;
+ int right;
+
+ int radiusOffset = mRadius * 2;
+ right = getWidth() - mBottom;
+ top = getHeight() / 2 - (mWidth / 2); /* (height of screen / 2) - (height of bar / 2) */
+ left = getWidth() - mBottom - radiusOffset;
+ bottom = getHeight() / 2 + (mWidth / 2);
+ canvas.drawRoundRect(left, top, right, bottom, mRadius, mRadius, mPaint);
+ }
+}