diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index ebb5f9f9e446d..f70d3c2a27fdd 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -132,6 +132,12 @@ oneway interface IStatusBar void clickQsTile(in ComponentName tile); void handleSystemKey(in int key); + /** + * Methods to show toast messages for screen pinning + */ + void showPinningEnterExitToast(boolean entering); + void showPinningEscapeToast(); + void showShutdownUi(boolean isReboot, String reason); // Used to show the dialog when FingerprintService starts authentication diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index cb0b53c495dcf..adf42878ebb3c 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -81,6 +81,12 @@ interface IStatusBarService void clickTile(in ComponentName tile); void handleSystemKey(in int key); + /** + * Methods to show toast messages for screen pinning + */ + void showPinningEnterExitToast(boolean entering); + void showPinningEscapeToast(); + // Used to show the dialog when FingerprintService starts authentication void showFingerprintDialog(in Bundle bundle, IFingerprintDialogReceiver receiver); // Used to hide the dialog when a finger is authenticated diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a24061621c3c3..731b6f7b632b5 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4423,15 +4423,6 @@ sans-serif-medium - - To unpin this screen, touch & hold Back and Overview - buttons - - - Screen pinned - - Screen unpinned - Ask for PIN before unpinning diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a338f89af201b..fee5a80245b4e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -767,9 +767,6 @@ - - - diff --git a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml index c2b1009c31370..a3118b0a5d913 100644 --- a/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml +++ b/packages/SystemUI/res/layout/screen_pinning_request_buttons.xml @@ -84,7 +84,25 @@ android:layout_height="@dimen/screen_pinning_request_button_height" android:layout_weight="0" android:paddingStart="@dimen/screen_pinning_request_frame_padding" - android:paddingEnd="@dimen/screen_pinning_request_frame_padding" > + android:paddingEnd="@dimen/screen_pinning_request_frame_padding" + android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent"> + + + + + android:layout_weight="0" + android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent"> + + + + + android:layout_weight="0" + android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent" > + + + + Screen is pinned This keeps it in view until you unpin. Touch & hold Back and Overview to unpin. + This keeps it in view until you unpin. Touch & hold Back and Home to unpin. This keeps it in view until you unpin. Touch & hold Overview to unpin. + This keeps it in view until you unpin. Touch & hold Home to unpin. + + To unpin this screen, touch & hold Back and Overview + buttons + To unpin this screen, touch & hold Back + and Home buttons Got it No thanks + + Screen pinned + Screen unpinned + Hide %1$s? diff --git a/packages/SystemUI/src/com/android/systemui/SysUIToast.java b/packages/SystemUI/src/com/android/systemui/SysUIToast.java index 89bc82f879307..43b918dbea73b 100644 --- a/packages/SystemUI/src/com/android/systemui/SysUIToast.java +++ b/packages/SystemUI/src/com/android/systemui/SysUIToast.java @@ -15,13 +15,19 @@ */ package com.android.systemui; +import android.annotation.StringRes; import android.content.Context; import android.view.WindowManager; import android.widget.Toast; +import static android.widget.Toast.Duration; public class SysUIToast { - public static Toast makeText(Context context, CharSequence text, int duration) { + public static Toast makeText(Context context, @StringRes int resId, @Duration int duration) { + return makeText(context, context.getString(resId), duration); + } + + public static Toast makeText(Context context, CharSequence text, @Duration int duration) { Toast toast = Toast.makeText(context, text, duration); toast.getWindowParams().privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 316ad1661898a..57f7818eae587 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -23,15 +23,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Configuration; import android.graphics.PixelFormat; -import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.os.Binder; import android.os.RemoteException; import android.util.DisplayMetrics; import android.view.Gravity; -import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -43,6 +40,9 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.android.systemui.R; +import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.statusbar.phone.NavigationBarView; +import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.leak.RotationUtils; import java.util.ArrayList; @@ -233,11 +233,30 @@ public class ScreenPinningRequest implements View.OnClickListener { .setVisibility(View.INVISIBLE); } + StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class); + NavigationBarView navigationBarView = statusBar.getNavigationBarView(); + final boolean recentsVisible = navigationBarView != null + && navigationBarView.isRecentsButtonVisible(); boolean touchExplorationEnabled = mAccessibilityService.isTouchExplorationEnabled(); + int descriptionStringResId; + if (recentsVisible) { + mLayout.findViewById(R.id.screen_pinning_recents_group).setVisibility(VISIBLE); + mLayout.findViewById(R.id.screen_pinning_home_bg_light).setVisibility(INVISIBLE); + mLayout.findViewById(R.id.screen_pinning_home_bg).setVisibility(INVISIBLE); + descriptionStringResId = touchExplorationEnabled + ? R.string.screen_pinning_description_accessible + : R.string.screen_pinning_description; + } else { + mLayout.findViewById(R.id.screen_pinning_recents_group).setVisibility(INVISIBLE); + mLayout.findViewById(R.id.screen_pinning_home_bg_light).setVisibility(VISIBLE); + mLayout.findViewById(R.id.screen_pinning_home_bg).setVisibility(VISIBLE); + descriptionStringResId = touchExplorationEnabled + ? R.string.screen_pinning_description_recents_invisible_accessible + : R.string.screen_pinning_description_recents_invisible; + } + ((TextView) mLayout.findViewById(R.id.screen_pinning_description)) - .setText(touchExplorationEnabled - ? R.string.screen_pinning_description_accessible - : R.string.screen_pinning_description); + .setText(descriptionStringResId); final int backBgVisibility = touchExplorationEnabled ? View.INVISIBLE : View.VISIBLE; mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility); mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 79e9f7b45d8d0..11bdf6b3c72e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -24,6 +24,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.support.annotation.VisibleForTesting; import android.util.Pair; @@ -90,6 +91,8 @@ public class CommandQueue extends IStatusBar.Stub { private static final int MSG_FINGERPRINT_ERROR = 42 << MSG_SHIFT; private static final int MSG_FINGERPRINT_HIDE = 43 << MSG_SHIFT; private static final int MSG_SHOW_CHARGING_ANIMATION = 44 << MSG_SHIFT; + private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT; + private static final int MSG_SHOW_PINNING_TOAST_ESCAPE = 46 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -148,6 +151,8 @@ public class CommandQueue extends IStatusBar.Stub { default void clickTile(ComponentName tile) { } default void handleSystemKey(int arg1) { } + default void showPinningEnterExitToast(boolean entering) { } + default void showPinningEscapeToast() { } default void handleShowGlobalActionsMenu() { } default void handleShowShutdownUi(boolean isReboot, String reason) { } @@ -452,6 +457,21 @@ public class CommandQueue extends IStatusBar.Stub { } } + @Override + public void showPinningEnterExitToast(boolean entering) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ENTER_EXIT, entering).sendToTarget(); + } + } + + @Override + public void showPinningEscapeToast() { + synchronized (mLock) { + mHandler.obtainMessage(MSG_SHOW_PINNING_TOAST_ESCAPE).sendToTarget(); + } + } + + @Override public void showGlobalActionsMenu() { synchronized (mLock) { @@ -767,6 +787,16 @@ public class CommandQueue extends IStatusBar.Stub { mCallbacks.get(i).showChargingAnimation(msg.arg1); } break; + case MSG_SHOW_PINNING_TOAST_ENTER_EXIT: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).showPinningEnterExitToast((Boolean) msg.obj); + } + break; + case MSG_SHOW_PINNING_TOAST_ESCAPE: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).showPinningEscapeToast(); + } + break; } } } 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 65c45a3120c1f..1239a9ea0240e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -22,11 +22,13 @@ import static android.app.StatusBarManager.windowStateToString; import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE; import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions; +import static com.android.systemui.OverviewProxyService.OverviewProxyListener; import android.accessibilityservice.AccessibilityServiceInfo; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; +import android.annotation.IdRes; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerNative; @@ -69,6 +71,7 @@ import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; +import android.widget.Button; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -153,6 +156,18 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private Animator mRotateShowAnimator; private Animator mRotateHideAnimator; + private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() { + @Override + public void onConnectionChanged(boolean isConnected) { + mNavigationBarView.onOverviewProxyConnectionChanged(isConnected); + updateScreenPinningGestures(); + } + + @Override + public void onRecentsAnimationStarted() { + mNavigationBarView.setRecentsAnimationStarted(true); + } + }; // ----- Fragment Lifecycle Callbacks ----- @@ -239,12 +254,14 @@ public class NavigationBarFragment extends Fragment implements Callbacks { filter.addAction(Intent.ACTION_SCREEN_ON); getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); notifyNavigationBarScreenOn(); + mOverviewProxyService.addCallback(mOverviewProxyListener); } @Override public void onDestroyView() { super.onDestroyView(); mNavigationBarView.getLightTransitionsController().destroy(getContext()); + mOverviewProxyService.removeCallback(mOverviewProxyListener); getContext().unregisterReceiver(mBroadcastReceiver); } @@ -514,6 +531,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { if (masked != mDisabledFlags1) { mDisabledFlags1 = masked; if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1); + updateScreenPinningGestures(); } } @@ -528,7 +546,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private boolean shouldDisableNavbarGestures() { return !mStatusBar.isDeviceProvisioned() || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0 - || mOverviewProxyService.getProxy() != null; + || mNavigationBarView.getRecentsButton().getVisibility() != View.VISIBLE; } private void repositionNavigationBar() { @@ -540,6 +558,24 @@ public class NavigationBarFragment extends Fragment implements Callbacks { ((View) mNavigationBarView.getParent()).getLayoutParams()); } + private void updateScreenPinningGestures() { + if (mNavigationBarView == null) { + return; + } + + // Change the cancel pin gesture to home and back if recents button is invisible + boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible(); + ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); + ButtonDispatcher backButton = mNavigationBarView.getBackButton(); + if (recentsVisible) { + homeButton.setOnLongClickListener(this::onHomeLongClick); + backButton.setOnLongClickListener(this::onLongPressBackRecents); + } else { + homeButton.setOnLongClickListener(this::onLongPressBackHome); + backButton.setOnLongClickListener(this::onLongPressBackHome); + } + } + private void notifyNavigationBarScreenOn() { mNavigationBarView.notifyScreenOn(); } @@ -555,11 +591,9 @@ public class NavigationBarFragment extends Fragment implements Callbacks { ButtonDispatcher backButton = mNavigationBarView.getBackButton(); backButton.setLongClickable(true); - backButton.setOnLongClickListener(this::onLongPressBackRecents); ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); homeButton.setOnTouchListener(this::onHomeTouch); - homeButton.setOnLongClickListener(this::onHomeLongClick); ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton(); accessibilityButton.setOnClickListener(this::onAccessibilityClick); @@ -569,6 +603,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton(); rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick); rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover); + updateScreenPinningGestures(); } private boolean onHomeTouch(View v, MotionEvent event) { @@ -649,20 +684,29 @@ public class NavigationBarFragment extends Fragment implements Callbacks { mCommandQueue.toggleRecentApps(); } + private boolean onLongPressBackHome(View v) { + return onLongPressNavigationButtons(v, R.id.back, R.id.home); + } + + private boolean onLongPressBackRecents(View v) { + return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps); + } + /** - * This handles long-press of both back and recents. They are - * handled together to capture them both being long-pressed + * This handles long-press of both back and recents/home. Back is the common button with + * combination of recents if it is visible or home if recents is invisible. + * They are handled together to capture them both being long-pressed * at the same time to exit screen pinning (lock task). * - * When accessibility mode is on, only a long-press from recents + * When accessibility mode is on, only a long-press from recents/home * is required to exit. * * In all other circumstances we try to pass through long-press events * for Back, so that apps can still use it. Which can be from two things. * 1) Not currently in screen pinning (lock task). - * 2) Back is long-pressed without recents. + * 2) Back is long-pressed without recents/home. */ - private boolean onLongPressBackRecents(View v) { + private boolean onLongPressNavigationButtons(View v, @IdRes int btnId1, @IdRes int btnId2) { try { boolean sendBackLongPress = false; IActivityManager activityManager = ActivityManagerNative.getDefault(); @@ -670,6 +714,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { boolean inLockTaskMode = activityManager.isInLockTaskMode(); if (inLockTaskMode && !touchExplorationEnabled) { long time = System.currentTimeMillis(); + // If we recently long-pressed the other button then they were // long-pressed 'together' if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) { @@ -677,26 +722,32 @@ public class NavigationBarFragment extends Fragment implements Callbacks { // When exiting refresh disabled flags. mNavigationBarView.setDisabledFlags(mDisabledFlags1, true); return true; - } else if ((v.getId() == R.id.back) - && !mNavigationBarView.getRecentsButton().getCurrentView().isPressed()) { - // If we aren't pressing recents right now then they presses - // won't be together, so send the standard long-press action. - sendBackLongPress = true; + } else if (v.getId() == btnId1) { + ButtonDispatcher button = btnId2 == R.id.recent_apps + ? mNavigationBarView.getRecentsButton() + : mNavigationBarView.getHomeButton(); + if (!button.getCurrentView().isPressed()) { + // If we aren't pressing recents/home right now then they presses + // won't be together, so send the standard long-press action. + sendBackLongPress = true; + } } mLastLockToAppLongPress = time; } else { // If this is back still need to handle sending the long-press event. - if (v.getId() == R.id.back) { + if (v.getId() == btnId1) { sendBackLongPress = true; } else if (touchExplorationEnabled && inLockTaskMode) { - // When in accessibility mode a long press that is recents (not back) + // When in accessibility mode a long press that is recents/home (not back) // should stop lock task. activityManager.stopSystemLockTaskMode(); // When exiting refresh disabled flags. mNavigationBarView.setDisabledFlags(mDisabledFlags1, true); return true; - } else if (v.getId() == R.id.recent_apps) { - return onLongPressRecents(); + } else if (v.getId() == btnId2) { + return btnId2 == R.id.recent_apps + ? onLongPressRecents() + : onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView()); } } if (sendBackLongPress) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index e04ba83419496..c37dd55cc6ffa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -207,23 +207,6 @@ public class NavigationBarView extends FrameLayout implements PluginListener