blob: 79c605e4ed231ac57b68d8c674ab8e03f2baa6a6 [file] [log] [blame]
Jason Monk49fa0162017-01-11 09:21:56 -05001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.statusbar.phone;
16
17import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
18import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
19import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
20import static android.app.StatusBarManager.windowStateToString;
21
Matthew Ng8f25fb962018-01-16 17:17:24 -080022import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
Jason Monk49fa0162017-01-11 09:21:56 -050023import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050024import static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
25import static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
Matthew Ng9c3bce52018-02-01 22:00:31 +000026import static com.android.systemui.OverviewProxyService.OverviewProxyListener;
Jason Monk49fa0162017-01-11 09:21:56 -050027
Casey Burkhardt048c2bc2016-12-08 16:09:20 -080028import android.accessibilityservice.AccessibilityServiceInfo;
Mike Digman7d092772018-01-11 12:10:32 -080029import android.animation.Animator;
30import android.animation.AnimatorListenerAdapter;
Mike Digman7d092772018-01-11 12:10:32 -080031import android.animation.ObjectAnimator;
Matthew Ng9c3bce52018-02-01 22:00:31 +000032import android.annotation.IdRes;
Jason Monk49fa0162017-01-11 09:21:56 -050033import android.annotation.Nullable;
34import android.app.ActivityManager;
35import android.app.ActivityManagerNative;
36import android.app.Fragment;
37import android.app.IActivityManager;
38import android.app.StatusBarManager;
39import android.content.BroadcastReceiver;
Casey Burkhardtb9dcd662017-03-20 15:10:16 -070040import android.content.ContentResolver;
Jason Monk49fa0162017-01-11 09:21:56 -050041import android.content.Context;
42import android.content.Intent;
43import android.content.IntentFilter;
44import android.content.res.Configuration;
Casey Burkhardt74922c62017-02-13 12:43:16 -080045import android.database.ContentObserver;
Jason Monk49fa0162017-01-11 09:21:56 -050046import android.graphics.PixelFormat;
47import android.graphics.Rect;
Mike Digman7d092772018-01-11 12:10:32 -080048import android.graphics.drawable.AnimatedVectorDrawable;
Jason Monk49fa0162017-01-11 09:21:56 -050049import android.inputmethodservice.InputMethodService;
50import android.os.Binder;
51import android.os.Bundle;
52import android.os.Handler;
53import android.os.IBinder;
54import android.os.Message;
Jason Monk49fa0162017-01-11 09:21:56 -050055import android.os.RemoteException;
56import android.os.UserHandle;
Casey Burkhardt74922c62017-02-13 12:43:16 -080057import android.provider.Settings;
Jason Monk865246d2017-01-19 08:27:01 -050058import android.support.annotation.VisibleForTesting;
Jason Monk49fa0162017-01-11 09:21:56 -050059import android.telecom.TelecomManager;
60import android.text.TextUtils;
61import android.util.Log;
62import android.view.IRotationWatcher.Stub;
63import android.view.KeyEvent;
64import android.view.LayoutInflater;
65import android.view.MotionEvent;
Mike Digman85ff7fa2018-01-23 14:59:52 -080066import android.view.Surface;
Jason Monk49fa0162017-01-11 09:21:56 -050067import android.view.View;
68import android.view.ViewGroup;
69import android.view.WindowManager;
70import android.view.WindowManager.LayoutParams;
71import android.view.WindowManagerGlobal;
72import android.view.accessibility.AccessibilityEvent;
73import android.view.accessibility.AccessibilityManager;
Jason Monk91e587e2017-04-13 13:41:23 -040074import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
Jason Monk49fa0162017-01-11 09:21:56 -050075
76import com.android.internal.logging.MetricsLogger;
77import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jason Monkea03be12017-12-04 11:08:41 -050078import com.android.internal.util.LatencyTracker;
Jason Monk9c7844c2017-01-18 15:21:53 -050079import com.android.systemui.Dependency;
Matthew Ngdc79e5c2017-12-14 17:37:35 -080080import com.android.systemui.OverviewProxyService;
Mike Digman7d092772018-01-11 12:10:32 -080081import com.android.systemui.Interpolators;
Jason Monk49fa0162017-01-11 09:21:56 -050082import com.android.systemui.R;
Jason Monk9c7844c2017-01-18 15:21:53 -050083import com.android.systemui.SysUiServiceProvider;
Jason Monk49fa0162017-01-11 09:21:56 -050084import com.android.systemui.assist.AssistManager;
85import com.android.systemui.fragments.FragmentHostManager;
86import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
87import com.android.systemui.recents.Recents;
Mike Digman7d092772018-01-11 12:10:32 -080088import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
89import com.android.systemui.shared.system.ActivityManagerWrapper;
Jason Monk49fa0162017-01-11 09:21:56 -050090import com.android.systemui.stackdivider.Divider;
91import com.android.systemui.statusbar.CommandQueue;
92import com.android.systemui.statusbar.CommandQueue.Callbacks;
Jason Monk91e587e2017-04-13 13:41:23 -040093import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
Mike Digman7d092772018-01-11 12:10:32 -080094import com.android.systemui.statusbar.policy.KeyButtonDrawable;
Jason Monk49fa0162017-01-11 09:21:56 -050095import com.android.systemui.statusbar.policy.KeyButtonView;
Mike Digman7d092772018-01-11 12:10:32 -080096import com.android.systemui.statusbar.policy.RotationLockController;
Jason Monk49fa0162017-01-11 09:21:56 -050097import com.android.systemui.statusbar.stack.StackStateAnimator;
98
99import java.io.FileDescriptor;
100import java.io.PrintWriter;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800101import java.util.List;
Jason Monk49fa0162017-01-11 09:21:56 -0500102import java.util.Locale;
103
104/**
105 * Fragment containing the NavigationBarFragment. Contains logic for what happens
106 * on clicks and view states of the nav bar.
107 */
108public class NavigationBarFragment extends Fragment implements Callbacks {
109
Jason Monkd4afe152017-05-01 15:37:43 -0400110 public static final String TAG = "NavigationBar";
Jason Monk49fa0162017-01-11 09:21:56 -0500111 private static final boolean DEBUG = false;
112 private static final String EXTRA_DISABLE_STATE = "disabled_state";
113
114 /** Allow some time inbetween the long press for back and recents. */
115 private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
116
117 protected NavigationBarView mNavigationBarView = null;
118 protected AssistManager mAssistManager;
119
120 private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
121
122 private int mNavigationIconHints = 0;
123 private int mNavigationBarMode;
Mike Digman90402952018-01-22 16:05:51 -0800124 private boolean mAccessibilityFeedbackEnabled;
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800125 private AccessibilityManager mAccessibilityManager;
Casey Burkhardt74922c62017-02-13 12:43:16 -0800126 private MagnificationContentObserver mMagnificationObserver;
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700127 private ContentResolver mContentResolver;
Mike Digmanc94759d2018-01-23 11:01:21 -0800128 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
Jason Monk49fa0162017-01-11 09:21:56 -0500129
130 private int mDisabledFlags1;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500131 private StatusBar mStatusBar;
Jason Monk49fa0162017-01-11 09:21:56 -0500132 private Recents mRecents;
133 private Divider mDivider;
134 private WindowManager mWindowManager;
135 private CommandQueue mCommandQueue;
136 private long mLastLockToAppLongPress;
137
138 private Locale mLocale;
139 private int mLayoutDirection;
140
141 private int mSystemUiVisibility;
142 private LightBarController mLightBarController;
Jason Monk49fa0162017-01-11 09:21:56 -0500143
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800144 private OverviewProxyService mOverviewProxyService;
145
Jason Monk49fa0162017-01-11 09:21:56 -0500146 public boolean mHomeBlockedThisTouch;
147
Mike Digman7d092772018-01-11 12:10:32 -0800148 private int mLastRotationSuggestion;
Mike Digman90402952018-01-22 16:05:51 -0800149 private boolean mHoveringRotationSuggestion;
Mike Digman7d092772018-01-11 12:10:32 -0800150 private RotationLockController mRotationLockController;
151 private TaskStackListenerImpl mTaskStackListener;
152
Mike Digmana48cf192018-02-12 17:52:48 -0800153 private final Runnable mRemoveRotationProposal = () -> safeSetRotationButtonState(false);
Mike Digman7d092772018-01-11 12:10:32 -0800154 private Animator mRotateShowAnimator;
155 private Animator mRotateHideAnimator;
156
Matthew Ng9c3bce52018-02-01 22:00:31 +0000157 private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
158 @Override
159 public void onConnectionChanged(boolean isConnected) {
160 mNavigationBarView.onOverviewProxyConnectionChanged(isConnected);
161 updateScreenPinningGestures();
162 }
163
164 @Override
165 public void onRecentsAnimationStarted() {
166 mNavigationBarView.setRecentsAnimationStarted(true);
167 }
Matthew Ng8f25fb962018-01-16 17:17:24 -0800168
169 @Override
170 public void onInteractionFlagsChanged(@InteractionType int flags) {
171 mNavigationBarView.updateStates();
172 }
Matthew Ng9c3bce52018-02-01 22:00:31 +0000173 };
Mike Digman7d092772018-01-11 12:10:32 -0800174
Jason Monk49fa0162017-01-11 09:21:56 -0500175 // ----- Fragment Lifecycle Callbacks -----
176
177 @Override
178 public void onCreate(@Nullable Bundle savedInstanceState) {
179 super.onCreate(savedInstanceState);
Jason Monk9c7844c2017-01-18 15:21:53 -0500180 mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
Jason Monk49fa0162017-01-11 09:21:56 -0500181 mCommandQueue.addCallbacks(this);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500182 mStatusBar = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
Jason Monk9c7844c2017-01-18 15:21:53 -0500183 mRecents = SysUiServiceProvider.getComponent(getContext(), Recents.class);
184 mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
Jason Monk49fa0162017-01-11 09:21:56 -0500185 mWindowManager = getContext().getSystemService(WindowManager.class);
186 mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
Jason Monk91e587e2017-04-13 13:41:23 -0400187 Dependency.get(AccessibilityManagerWrapper.class).addCallback(
188 mAccessibilityListener);
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700189 mContentResolver = getContext().getContentResolver();
Casey Burkhardt74922c62017-02-13 12:43:16 -0800190 mMagnificationObserver = new MagnificationContentObserver(
191 getContext().getMainThreadHandler());
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700192 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
Casey Burkhardt74922c62017-02-13 12:43:16 -0800193 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED), false,
Casey Burkhardt5d614402017-04-06 13:46:50 -0700194 mMagnificationObserver, UserHandle.USER_ALL);
Casey Burkhardt74922c62017-02-13 12:43:16 -0800195
Jason Monk49fa0162017-01-11 09:21:56 -0500196 if (savedInstanceState != null) {
197 mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
198 }
Jason Monk9c7844c2017-01-18 15:21:53 -0500199 mAssistManager = Dependency.get(AssistManager.class);
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800200 mOverviewProxyService = Dependency.get(OverviewProxyService.class);
Jason Monk49fa0162017-01-11 09:21:56 -0500201
202 try {
203 WindowManagerGlobal.getWindowManagerService()
Andrii Kulian35fa3c22017-03-11 09:37:28 -0800204 .watchRotation(mRotationWatcher, getContext().getDisplay().getDisplayId());
Jason Monk49fa0162017-01-11 09:21:56 -0500205 } catch (RemoteException e) {
206 throw e.rethrowFromSystemServer();
207 }
Mike Digman7d092772018-01-11 12:10:32 -0800208
209 mRotationLockController = Dependency.get(RotationLockController.class);
210
211 // Register the task stack listener
212 mTaskStackListener = new TaskStackListenerImpl();
213 ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
Jason Monk49fa0162017-01-11 09:21:56 -0500214 }
215
216 @Override
217 public void onDestroy() {
218 super.onDestroy();
219 mCommandQueue.removeCallbacks(this);
Jason Monk91e587e2017-04-13 13:41:23 -0400220 Dependency.get(AccessibilityManagerWrapper.class).removeCallback(
221 mAccessibilityListener);
Casey Burkhardtb9dcd662017-03-20 15:10:16 -0700222 mContentResolver.unregisterContentObserver(mMagnificationObserver);
Jason Monk49fa0162017-01-11 09:21:56 -0500223 try {
224 WindowManagerGlobal.getWindowManagerService()
225 .removeRotationWatcher(mRotationWatcher);
226 } catch (RemoteException e) {
227 throw e.rethrowFromSystemServer();
228 }
Mike Digman7d092772018-01-11 12:10:32 -0800229
230 // Unregister the task stack listener
231 ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
Jason Monk49fa0162017-01-11 09:21:56 -0500232 }
233
234 @Override
235 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
236 Bundle savedInstanceState) {
237 return inflater.inflate(R.layout.navigation_bar, container, false);
238 }
239
240 @Override
241 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
242 super.onViewCreated(view, savedInstanceState);
243 mNavigationBarView = (NavigationBarView) view;
244
245 mNavigationBarView.setDisabledFlags(mDisabledFlags1);
Matthew Ng78f88d12018-01-23 12:39:55 -0800246 mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel());
Jason Monk49fa0162017-01-11 09:21:56 -0500247 mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
248 mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
249 if (savedInstanceState != null) {
250 mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState);
251 }
252
253 prepareNavigationBarView();
254 checkNavBarModes();
255
256 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
257 filter.addAction(Intent.ACTION_SCREEN_ON);
258 getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
Siarhei Vishniakoud002a0a2017-06-05 22:44:37 +0100259 notifyNavigationBarScreenOn();
Matthew Ng9c3bce52018-02-01 22:00:31 +0000260 mOverviewProxyService.addCallback(mOverviewProxyListener);
Jason Monk49fa0162017-01-11 09:21:56 -0500261 }
262
263 @Override
264 public void onDestroyView() {
265 super.onDestroyView();
Jason Monkaa573e92017-01-27 17:00:29 -0500266 mNavigationBarView.getLightTransitionsController().destroy(getContext());
Matthew Ng9c3bce52018-02-01 22:00:31 +0000267 mOverviewProxyService.removeCallback(mOverviewProxyListener);
Jason Monk49fa0162017-01-11 09:21:56 -0500268 getContext().unregisterReceiver(mBroadcastReceiver);
269 }
270
271 @Override
272 public void onSaveInstanceState(Bundle outState) {
273 super.onSaveInstanceState(outState);
274 outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1);
275 if (mNavigationBarView != null) {
276 mNavigationBarView.getLightTransitionsController().saveState(outState);
277 }
278 }
279
280 @Override
281 public void onConfigurationChanged(Configuration newConfig) {
282 super.onConfigurationChanged(newConfig);
283 final Locale locale = getContext().getResources().getConfiguration().locale;
284 final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
285 if (!locale.equals(mLocale) || ld != mLayoutDirection) {
286 if (DEBUG) {
287 Log.v(TAG, String.format(
288 "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
289 locale, ld));
290 }
291 mLocale = locale;
292 mLayoutDirection = ld;
293 refreshLayout(ld);
294 }
295 repositionNavigationBar();
296 }
297
298 @Override
299 public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
300 if (mNavigationBarView != null) {
301 pw.print(" mNavigationBarWindowState=");
302 pw.println(windowStateToString(mNavigationBarWindowState));
303 pw.print(" mNavigationBarMode=");
304 pw.println(BarTransitions.modeToString(mNavigationBarMode));
305 dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
306 }
307
308 pw.print(" mNavigationBarView=");
309 if (mNavigationBarView == null) {
310 pw.println("null");
311 } else {
312 mNavigationBarView.dump(fd, pw, args);
313 }
314 }
315
316 // ----- CommandQueue Callbacks -----
317
318 @Override
319 public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
320 boolean showImeSwitcher) {
321 boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
322 int hints = mNavigationIconHints;
Tarandeep Singh3fecef12018-01-22 14:33:33 -0800323 if (imeShown && backDisposition != InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS) {
Jason Monk49fa0162017-01-11 09:21:56 -0500324 hints |= NAVIGATION_HINT_BACK_ALT;
325 } else {
326 hints &= ~NAVIGATION_HINT_BACK_ALT;
327 }
328 if (showImeSwitcher) {
329 hints |= NAVIGATION_HINT_IME_SHOWN;
330 } else {
331 hints &= ~NAVIGATION_HINT_IME_SHOWN;
332 }
333 if (hints == mNavigationIconHints) return;
334
335 mNavigationIconHints = hints;
336
337 if (mNavigationBarView != null) {
338 mNavigationBarView.setNavigationIconHints(hints);
339 }
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500340 mStatusBar.checkBarModes();
Jason Monk49fa0162017-01-11 09:21:56 -0500341 }
342
343 @Override
344 public void topAppWindowChanged(boolean showMenu) {
345 if (mNavigationBarView != null) {
346 mNavigationBarView.setMenuVisibility(showMenu);
347 }
348 }
349
350 @Override
351 public void setWindowState(int window, int state) {
352 if (mNavigationBarView != null
353 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
354 && mNavigationBarWindowState != state) {
355 mNavigationBarWindowState = state;
356 if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
357 }
358 }
359
Mike Digman7d092772018-01-11 12:10:32 -0800360 @Override
Mike Digmane0777312018-01-19 12:41:51 -0800361 public void onRotationProposal(final int rotation, boolean isValid) {
362 // This method will be called on rotation suggestion changes even if the proposed rotation
363 // is not valid for the top app. Use invalid rotation choices as a signal to remove the
364 // rotate button if shown.
365
366 if (!isValid) {
Mike Digmana48cf192018-02-12 17:52:48 -0800367 safeSetRotationButtonState(false);
Mike Digmane0777312018-01-19 12:41:51 -0800368 return;
369 }
370
Mike Digman7d092772018-01-11 12:10:32 -0800371 if (rotation == mWindowManager.getDefaultDisplay().getRotation()) {
372 // Use this as a signal to remove any current suggestions
Mike Digman90402952018-01-22 16:05:51 -0800373 getView().getHandler().removeCallbacks(mRemoveRotationProposal);
Mike Digmana48cf192018-02-12 17:52:48 -0800374 safeSetRotationButtonState(false);
Mike Digman7d092772018-01-11 12:10:32 -0800375 } else {
376 mLastRotationSuggestion = rotation; // Remember rotation for click
Mike Digmana48cf192018-02-12 17:52:48 -0800377 safeSetRotationButtonState(true);
Mike Digman90402952018-01-22 16:05:51 -0800378 rescheduleRotationTimeout(false);
Mike Digmanc94759d2018-01-23 11:01:21 -0800379 mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
Mike Digman7d092772018-01-11 12:10:32 -0800380 }
381 }
382
Mike Digmana48cf192018-02-12 17:52:48 -0800383 private void safeSetRotationButtonState(boolean vis) {
384 if (mNavigationBarView != null) mNavigationBarView.setRotateSuggestionButtonState(vis);
385 }
386
387 private void safeSetRotationButtonState(boolean vis, boolean force) {
388 if (mNavigationBarView != null) {
389 mNavigationBarView.setRotateSuggestionButtonState(vis, force);
390 }
391 }
392
Mike Digman90402952018-01-22 16:05:51 -0800393 private void rescheduleRotationTimeout(final boolean reasonHover) {
394 // May be called due to a new rotation proposal or a change in hover state
395 if (reasonHover) {
396 // Don't reschedule if a hide animator is running
397 if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
398 return;
399 }
400 // Don't reschedule if not visible
401 if (mNavigationBarView.getRotateSuggestionButton().getVisibility() != View.VISIBLE) {
402 return;
403 }
404 }
405
406 Handler h = getView().getHandler();
407 h.removeCallbacks(mRemoveRotationProposal); // Stop any pending removal
408 h.postDelayed(mRemoveRotationProposal,
409 computeRotationProposalTimeout()); // Schedule timeout
410 }
411
412 private int computeRotationProposalTimeout() {
413 if (mAccessibilityFeedbackEnabled) return 20000;
414 if (mHoveringRotationSuggestion) return 16000;
415 return 6000;
416 }
417
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500418 // Injected from StatusBar at creation.
Jason Monk49fa0162017-01-11 09:21:56 -0500419 public void setCurrentSysuiVisibility(int systemUiVisibility) {
420 mSystemUiVisibility = systemUiVisibility;
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500421 mNavigationBarMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
Jason Monk49fa0162017-01-11 09:21:56 -0500422 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
423 View.NAVIGATION_BAR_TRANSPARENT);
424 checkNavBarModes();
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500425 mStatusBar.touchAutoHide();
Jason Monk49fa0162017-01-11 09:21:56 -0500426 mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
427 true /* nbModeChanged */, mNavigationBarMode);
428 }
429
430 @Override
431 public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
432 int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
433 final int oldVal = mSystemUiVisibility;
434 final int newVal = (oldVal & ~mask) | (vis & mask);
435 final int diff = newVal ^ oldVal;
436 boolean nbModeChanged = false;
437 if (diff != 0) {
438 mSystemUiVisibility = newVal;
439
440 // update navigation bar mode
441 final int nbMode = getView() == null
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500442 ? -1 : mStatusBar.computeBarMode(oldVal, newVal,
Jason Monk49fa0162017-01-11 09:21:56 -0500443 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
444 View.NAVIGATION_BAR_TRANSPARENT);
445 nbModeChanged = nbMode != -1;
446 if (nbModeChanged) {
447 if (mNavigationBarMode != nbMode) {
448 mNavigationBarMode = nbMode;
449 checkNavBarModes();
450 }
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500451 mStatusBar.touchAutoHide();
Jason Monk49fa0162017-01-11 09:21:56 -0500452 }
453 }
454
455 mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
456 mNavigationBarMode);
457 }
458
459 @Override
460 public void disable(int state1, int state2, boolean animate) {
461 // All navigation bar flags are in state1.
462 int masked = state1 & (StatusBarManager.DISABLE_HOME
463 | StatusBarManager.DISABLE_RECENT
464 | StatusBarManager.DISABLE_BACK
465 | StatusBarManager.DISABLE_SEARCH);
466 if (masked != mDisabledFlags1) {
467 mDisabledFlags1 = masked;
468 if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
Matthew Ng9c3bce52018-02-01 22:00:31 +0000469 updateScreenPinningGestures();
Jason Monk49fa0162017-01-11 09:21:56 -0500470 }
471 }
472
473 // ----- Internal stuffz -----
474
475 private void refreshLayout(int layoutDirection) {
476 if (mNavigationBarView != null) {
477 mNavigationBarView.setLayoutDirection(layoutDirection);
478 }
479 }
480
481 private boolean shouldDisableNavbarGestures() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500482 return !mStatusBar.isDeviceProvisioned()
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800483 || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0
Matthew Ng9c3bce52018-02-01 22:00:31 +0000484 || mNavigationBarView.getRecentsButton().getVisibility() != View.VISIBLE;
Jason Monk49fa0162017-01-11 09:21:56 -0500485 }
486
487 private void repositionNavigationBar() {
488 if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
489
490 prepareNavigationBarView();
491
492 mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(),
493 ((View) mNavigationBarView.getParent()).getLayoutParams());
494 }
495
Matthew Ng9c3bce52018-02-01 22:00:31 +0000496 private void updateScreenPinningGestures() {
497 if (mNavigationBarView == null) {
498 return;
499 }
500
501 // Change the cancel pin gesture to home and back if recents button is invisible
502 boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
503 ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
504 ButtonDispatcher backButton = mNavigationBarView.getBackButton();
505 if (recentsVisible) {
506 homeButton.setOnLongClickListener(this::onHomeLongClick);
507 backButton.setOnLongClickListener(this::onLongPressBackRecents);
508 } else {
509 homeButton.setOnLongClickListener(this::onLongPressBackHome);
510 backButton.setOnLongClickListener(this::onLongPressBackHome);
511 }
512 }
513
Siarhei Vishniakoud002a0a2017-06-05 22:44:37 +0100514 private void notifyNavigationBarScreenOn() {
515 mNavigationBarView.notifyScreenOn();
Jason Monk49fa0162017-01-11 09:21:56 -0500516 }
517
518 private void prepareNavigationBarView() {
519 mNavigationBarView.reorient();
520
521 ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
522 recentsButton.setOnClickListener(this::onRecentsClick);
523 recentsButton.setOnTouchListener(this::onRecentsTouch);
524 recentsButton.setLongClickable(true);
525 recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
526
527 ButtonDispatcher backButton = mNavigationBarView.getBackButton();
528 backButton.setLongClickable(true);
Jason Monk49fa0162017-01-11 09:21:56 -0500529
530 ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
531 homeButton.setOnTouchListener(this::onHomeTouch);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800532
533 ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
534 accessibilityButton.setOnClickListener(this::onAccessibilityClick);
535 accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
Phil Weaverdb9a7742017-04-18 08:15:06 -0700536 updateAccessibilityServicesState(mAccessibilityManager);
Mike Digman7d092772018-01-11 12:10:32 -0800537
538 ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
539 rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
Mike Digman90402952018-01-22 16:05:51 -0800540 rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover);
Matthew Ng9c3bce52018-02-01 22:00:31 +0000541 updateScreenPinningGestures();
Jason Monk49fa0162017-01-11 09:21:56 -0500542 }
543
544 private boolean onHomeTouch(View v, MotionEvent event) {
545 if (mHomeBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
546 return true;
547 }
548 // If an incoming call is ringing, HOME is totally disabled.
549 // (The user is already on the InCallUI at this point,
550 // and his ONLY options are to answer or reject the call.)
551 switch (event.getAction()) {
552 case MotionEvent.ACTION_DOWN:
553 mHomeBlockedThisTouch = false;
554 TelecomManager telecomManager =
555 getContext().getSystemService(TelecomManager.class);
556 if (telecomManager != null && telecomManager.isRinging()) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500557 if (mStatusBar.isKeyguardShowing()) {
Jason Monk49fa0162017-01-11 09:21:56 -0500558 Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
559 "No heads up");
560 mHomeBlockedThisTouch = true;
561 return true;
562 }
563 }
564 break;
565 case MotionEvent.ACTION_UP:
566 case MotionEvent.ACTION_CANCEL:
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500567 mStatusBar.awakenDreams();
Jason Monk49fa0162017-01-11 09:21:56 -0500568 break;
569 }
570 return false;
571 }
572
573 private void onVerticalChanged(boolean isVertical) {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500574 mStatusBar.setQsScrimEnabled(!isVertical);
Jason Monk49fa0162017-01-11 09:21:56 -0500575 }
576
577 private boolean onNavigationTouch(View v, MotionEvent event) {
Eliot Courtneycb5d3162017-08-09 16:53:15 +0900578 mStatusBar.checkUserAutohide(event);
Jason Monk49fa0162017-01-11 09:21:56 -0500579 return false;
580 }
581
Jason Monk865246d2017-01-19 08:27:01 -0500582 @VisibleForTesting
583 boolean onHomeLongClick(View v) {
Jason Monk49fa0162017-01-11 09:21:56 -0500584 if (shouldDisableNavbarGestures()) {
585 return false;
586 }
Mike Digmanc94759d2018-01-23 11:01:21 -0800587 mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
Jason Monk49fa0162017-01-11 09:21:56 -0500588 mAssistManager.startAssist(new Bundle() /* args */);
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500589 mStatusBar.awakenDreams();
Matthew Ngdc79e5c2017-12-14 17:37:35 -0800590
Jason Monk49fa0162017-01-11 09:21:56 -0500591 if (mNavigationBarView != null) {
592 mNavigationBarView.abortCurrentGesture();
593 }
594 return true;
595 }
596
597 // additional optimization when we have software system buttons - start loading the recent
598 // tasks on touch down
599 private boolean onRecentsTouch(View v, MotionEvent event) {
600 int action = event.getAction() & MotionEvent.ACTION_MASK;
601 if (action == MotionEvent.ACTION_DOWN) {
602 mCommandQueue.preloadRecentApps();
603 } else if (action == MotionEvent.ACTION_CANCEL) {
604 mCommandQueue.cancelPreloadRecentApps();
605 } else if (action == MotionEvent.ACTION_UP) {
606 if (!v.isPressed()) {
607 mCommandQueue.cancelPreloadRecentApps();
608 }
609 }
610 return false;
611 }
612
613 private void onRecentsClick(View v) {
614 if (LatencyTracker.isEnabled(getContext())) {
615 LatencyTracker.getInstance(getContext()).onActionStart(
616 LatencyTracker.ACTION_TOGGLE_RECENTS);
617 }
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500618 mStatusBar.awakenDreams();
Jason Monk49fa0162017-01-11 09:21:56 -0500619 mCommandQueue.toggleRecentApps();
620 }
621
Matthew Ng9c3bce52018-02-01 22:00:31 +0000622 private boolean onLongPressBackHome(View v) {
623 return onLongPressNavigationButtons(v, R.id.back, R.id.home);
624 }
625
626 private boolean onLongPressBackRecents(View v) {
627 return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
628 }
629
Jason Monk49fa0162017-01-11 09:21:56 -0500630 /**
Matthew Ng9c3bce52018-02-01 22:00:31 +0000631 * This handles long-press of both back and recents/home. Back is the common button with
632 * combination of recents if it is visible or home if recents is invisible.
633 * They are handled together to capture them both being long-pressed
Jason Monk49fa0162017-01-11 09:21:56 -0500634 * at the same time to exit screen pinning (lock task).
635 *
Matthew Ng9c3bce52018-02-01 22:00:31 +0000636 * When accessibility mode is on, only a long-press from recents/home
Jason Monk49fa0162017-01-11 09:21:56 -0500637 * is required to exit.
638 *
639 * In all other circumstances we try to pass through long-press events
640 * for Back, so that apps can still use it. Which can be from two things.
641 * 1) Not currently in screen pinning (lock task).
Matthew Ng9c3bce52018-02-01 22:00:31 +0000642 * 2) Back is long-pressed without recents/home.
Jason Monk49fa0162017-01-11 09:21:56 -0500643 */
Matthew Ng9c3bce52018-02-01 22:00:31 +0000644 private boolean onLongPressNavigationButtons(View v, @IdRes int btnId1, @IdRes int btnId2) {
Jason Monk49fa0162017-01-11 09:21:56 -0500645 try {
646 boolean sendBackLongPress = false;
647 IActivityManager activityManager = ActivityManagerNative.getDefault();
648 boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
649 boolean inLockTaskMode = activityManager.isInLockTaskMode();
650 if (inLockTaskMode && !touchExplorationEnabled) {
651 long time = System.currentTimeMillis();
Matthew Ng9c3bce52018-02-01 22:00:31 +0000652
Jason Monk49fa0162017-01-11 09:21:56 -0500653 // If we recently long-pressed the other button then they were
654 // long-pressed 'together'
655 if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
Benjamin Franza83859f2017-07-03 16:34:14 +0100656 activityManager.stopSystemLockTaskMode();
Jason Monk49fa0162017-01-11 09:21:56 -0500657 // When exiting refresh disabled flags.
658 mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
659 return true;
Matthew Ng9c3bce52018-02-01 22:00:31 +0000660 } else if (v.getId() == btnId1) {
661 ButtonDispatcher button = btnId2 == R.id.recent_apps
662 ? mNavigationBarView.getRecentsButton()
663 : mNavigationBarView.getHomeButton();
664 if (!button.getCurrentView().isPressed()) {
665 // If we aren't pressing recents/home right now then they presses
666 // won't be together, so send the standard long-press action.
667 sendBackLongPress = true;
668 }
Jason Monk49fa0162017-01-11 09:21:56 -0500669 }
670 mLastLockToAppLongPress = time;
671 } else {
672 // If this is back still need to handle sending the long-press event.
Matthew Ng9c3bce52018-02-01 22:00:31 +0000673 if (v.getId() == btnId1) {
Jason Monk49fa0162017-01-11 09:21:56 -0500674 sendBackLongPress = true;
675 } else if (touchExplorationEnabled && inLockTaskMode) {
Matthew Ng9c3bce52018-02-01 22:00:31 +0000676 // When in accessibility mode a long press that is recents/home (not back)
Jason Monk49fa0162017-01-11 09:21:56 -0500677 // should stop lock task.
Benjamin Franza83859f2017-07-03 16:34:14 +0100678 activityManager.stopSystemLockTaskMode();
Jason Monk49fa0162017-01-11 09:21:56 -0500679 // When exiting refresh disabled flags.
680 mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
681 return true;
Matthew Ng9c3bce52018-02-01 22:00:31 +0000682 } else if (v.getId() == btnId2) {
683 return btnId2 == R.id.recent_apps
684 ? onLongPressRecents()
685 : onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView());
Jason Monk49fa0162017-01-11 09:21:56 -0500686 }
687 }
688 if (sendBackLongPress) {
689 KeyButtonView keyButtonView = (KeyButtonView) v;
690 keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
691 keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
692 return true;
693 }
694 } catch (RemoteException e) {
695 Log.d(TAG, "Unable to reach activity manager", e);
696 }
697 return false;
698 }
699
700 private boolean onLongPressRecents() {
Erik Wolsheimer9be3a062017-05-31 14:59:57 -0700701 if (mRecents == null || !ActivityManager.supportsMultiWindow(getContext())
Matthew Ng43db6d22017-06-27 15:29:39 -0700702 || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
703 || Recents.getConfiguration().isLowRamDevice) {
Jason Monk49fa0162017-01-11 09:21:56 -0500704 return false;
705 }
706
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500707 return mStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
Jason Monk49fa0162017-01-11 09:21:56 -0500708 MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
709 }
710
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800711 private void onAccessibilityClick(View v) {
712 mAccessibilityManager.notifyAccessibilityButtonClicked();
713 }
714
715 private boolean onAccessibilityLongClick(View v) {
Casey Burkhardt5e8b9802017-03-24 10:07:20 -0700716 Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
717 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Casey Burkhardt5d614402017-04-06 13:46:50 -0700718 v.getContext().startActivityAsUser(intent, UserHandle.CURRENT);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800719 return true;
720 }
721
Phil Weaverdb9a7742017-04-18 08:15:06 -0700722 private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800723 int requestingServices = 0;
724 try {
Casey Burkhardt5d614402017-04-06 13:46:50 -0700725 if (Settings.Secure.getIntForUser(mContentResolver,
726 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
727 UserHandle.USER_CURRENT) == 1) {
Casey Burkhardt74922c62017-02-13 12:43:16 -0800728 requestingServices++;
729 }
730 } catch (Settings.SettingNotFoundException e) {
731 }
732
Mike Digman90402952018-01-22 16:05:51 -0800733 boolean feedbackEnabled = false;
Casey Burkhardt5d614402017-04-06 13:46:50 -0700734 // AccessibilityManagerService resolves services for the current user since the local
735 // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800736 final List<AccessibilityServiceInfo> services =
Phil Weaverdb9a7742017-04-18 08:15:06 -0700737 accessibilityManager.getEnabledAccessibilityServiceList(
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800738 AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800739 for (int i = services.size() - 1; i >= 0; --i) {
740 AccessibilityServiceInfo info = services.get(i);
741 if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
742 requestingServices++;
743 }
Mike Digman90402952018-01-22 16:05:51 -0800744
745 if (info.feedbackType != 0 && info.feedbackType !=
746 AccessibilityServiceInfo.FEEDBACK_GENERIC) {
747 feedbackEnabled = true;
748 }
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800749 }
750
Mike Digman90402952018-01-22 16:05:51 -0800751 mAccessibilityFeedbackEnabled = feedbackEnabled;
752
Casey Burkhardt048c2bc2016-12-08 16:09:20 -0800753 final boolean showAccessibilityButton = requestingServices >= 1;
754 final boolean targetSelection = requestingServices >= 2;
755 mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
756 }
757
Mike Digman7d092772018-01-11 12:10:32 -0800758 private void onRotateSuggestionClick(View v) {
Mike Digmanc94759d2018-01-23 11:01:21 -0800759 mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
Mike Digman7d092772018-01-11 12:10:32 -0800760 mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
761 }
762
Mike Digman90402952018-01-22 16:05:51 -0800763 private boolean onRotateSuggestionHover(View v, MotionEvent event) {
764 final int action = event.getActionMasked();
765 mHoveringRotationSuggestion = (action == MotionEvent.ACTION_HOVER_ENTER)
766 || (action == MotionEvent.ACTION_HOVER_MOVE);
767 rescheduleRotationTimeout(true);
768 return false; // Must return false so a11y hover events are dispatched correctly.
769 }
770
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500771 // ----- Methods that StatusBar talks to (should be minimized) -----
Jason Monk49fa0162017-01-11 09:21:56 -0500772
Jason Monk49fa0162017-01-11 09:21:56 -0500773 public void setLightBarController(LightBarController lightBarController) {
774 mLightBarController = lightBarController;
775 mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
776 }
777
778 public boolean isSemiTransparent() {
779 return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
780 }
781
Jason Monk49fa0162017-01-11 09:21:56 -0500782 public void disableAnimationsDuringHide(long delay) {
783 mNavigationBarView.setLayoutTransitionsEnabled(false);
784 mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
785 delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
786 }
787
Jason Monk49fa0162017-01-11 09:21:56 -0500788 public BarTransitions getBarTransitions() {
789 return mNavigationBarView.getBarTransitions();
790 }
791
792 public void checkNavBarModes() {
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500793 mStatusBar.checkBarMode(mNavigationBarMode,
Jason Monk49fa0162017-01-11 09:21:56 -0500794 mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
795 }
796
797 public void finishBarAnimations() {
798 mNavigationBarView.getBarTransitions().finishAnimations();
799 }
800
Jason Monk91e587e2017-04-13 13:41:23 -0400801 private final AccessibilityServicesStateChangeListener mAccessibilityListener =
802 this::updateAccessibilityServicesState;
803
Casey Burkhardt74922c62017-02-13 12:43:16 -0800804 private class MagnificationContentObserver extends ContentObserver {
805
806 public MagnificationContentObserver(Handler handler) {
807 super(handler);
808 }
809
810 @Override
811 public void onChange(boolean selfChange) {
Phil Weaverdb9a7742017-04-18 08:15:06 -0700812 NavigationBarFragment.this.updateAccessibilityServicesState(mAccessibilityManager);
Casey Burkhardt74922c62017-02-13 12:43:16 -0800813 }
814 }
815
Jason Monk49fa0162017-01-11 09:21:56 -0500816 private final Stub mRotationWatcher = new Stub() {
817 @Override
Mike Digman90402952018-01-22 16:05:51 -0800818 public void onRotationChanged(final int rotation) throws RemoteException {
Jason Monk49fa0162017-01-11 09:21:56 -0500819 // We need this to be scheduled as early as possible to beat the redrawing of
820 // window in response to the orientation change.
821 Handler h = getView().getHandler();
822 Message msg = Message.obtain(h, () -> {
Mike Digman85ff7fa2018-01-23 14:59:52 -0800823
824 // If the screen rotation changes while locked, potentially update lock to flow with
Mike Digman90402952018-01-22 16:05:51 -0800825 // new screen rotation and hide any showing suggestions.
826 if (mRotationLockController.isRotationLocked()) {
Mike Digman85ff7fa2018-01-23 14:59:52 -0800827 if (shouldOverrideUserLockPrefs(rotation)) {
828 mRotationLockController.setRotationLockedAtAngle(true, rotation);
829 }
Mike Digmana48cf192018-02-12 17:52:48 -0800830 safeSetRotationButtonState(false, true);
Mike Digman90402952018-01-22 16:05:51 -0800831 }
832
Jason Monk49fa0162017-01-11 09:21:56 -0500833 if (mNavigationBarView != null
834 && mNavigationBarView.needsReorient(rotation)) {
835 repositionNavigationBar();
836 }
837 });
838 msg.setAsynchronous(true);
839 h.sendMessageAtFrontOfQueue(msg);
840 }
Mike Digman85ff7fa2018-01-23 14:59:52 -0800841
842 private boolean shouldOverrideUserLockPrefs(final int rotation) {
843 // Only override user prefs when returning to portrait.
844 // Don't let apps that force landscape or 180 alter user lock.
845 return rotation == Surface.ROTATION_0;
846 }
Jason Monk49fa0162017-01-11 09:21:56 -0500847 };
848
849 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
850 @Override
851 public void onReceive(Context context, Intent intent) {
852 String action = intent.getAction();
Siarhei Vishniakoud002a0a2017-06-05 22:44:37 +0100853 if (Intent.ACTION_SCREEN_OFF.equals(action)
854 || Intent.ACTION_SCREEN_ON.equals(action)) {
855 notifyNavigationBarScreenOn();
Jason Monk49fa0162017-01-11 09:21:56 -0500856 }
857 }
858 };
859
Mike Digman7d092772018-01-11 12:10:32 -0800860 class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
861 // Invalidate any rotation suggestion on task change or activity orientation change
862 // Note: all callbacks happen on main thread
863
864 @Override
865 public void onTaskStackChanged() {
Mike Digmana48cf192018-02-12 17:52:48 -0800866 safeSetRotationButtonState(false);
Mike Digman7d092772018-01-11 12:10:32 -0800867 }
868
869 @Override
870 public void onTaskRemoved(int taskId) {
Mike Digmana48cf192018-02-12 17:52:48 -0800871 safeSetRotationButtonState(false);
Mike Digman7d092772018-01-11 12:10:32 -0800872 }
873
874 @Override
875 public void onTaskMovedToFront(int taskId) {
Mike Digmana48cf192018-02-12 17:52:48 -0800876 safeSetRotationButtonState(false);
Mike Digman7d092772018-01-11 12:10:32 -0800877 }
878
879 @Override
880 public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
Mike Digmana48cf192018-02-12 17:52:48 -0800881 safeSetRotationButtonState(false);
Mike Digman7d092772018-01-11 12:10:32 -0800882 }
883 }
884
Jason Monk49fa0162017-01-11 09:21:56 -0500885 public static View create(Context context, FragmentListener listener) {
886 WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
887 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
888 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
889 WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
890 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
891 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
892 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
893 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
894 | WindowManager.LayoutParams.FLAG_SLIPPERY,
895 PixelFormat.TRANSLUCENT);
896 lp.token = new Binder();
Jason Monk49fa0162017-01-11 09:21:56 -0500897 lp.setTitle("NavigationBar");
Phil Weaver8583ae82018-02-13 11:01:24 -0800898 lp.accessibilityTitle = context.getString(R.string.nav_bar);
Jason Monk49fa0162017-01-11 09:21:56 -0500899 lp.windowAnimations = 0;
900
901 View navigationBarView = LayoutInflater.from(context).inflate(
902 R.layout.navigation_bar_window, null);
903
904 if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
905 if (navigationBarView == null) return null;
906
907 context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
908 FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView);
909 NavigationBarFragment fragment = new NavigationBarFragment();
910 fragmentHost.getFragmentManager().beginTransaction()
911 .replace(R.id.navigation_bar_frame, fragment, TAG)
912 .commit();
913 fragmentHost.addTagListener(TAG, listener);
914 return navigationBarView;
915 }
916}