blob: 83c4cfc6c126bf1929bc8b9a3b0cc86e56a777db [file] [log] [blame]
Matthew Ng13dbf872017-10-27 11:02:14 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
Winson Chung2dbcf092018-10-24 13:00:41 -070017package com.android.systemui.recents;
Matthew Ng13dbf872017-10-27 11:02:14 -070018
Winson Chung67f5c8b2018-09-24 12:09:19 -070019import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
Gus Prevasab336792018-11-14 13:52:20 -050020import static android.view.MotionEvent.ACTION_CANCEL;
Hyunyoung Song547e11e2018-10-04 16:32:23 -070021import static android.view.MotionEvent.ACTION_DOWN;
22import static android.view.MotionEvent.ACTION_UP;
Hyunyoung Song547e11e2018-10-04 16:32:23 -070023
Winson Chung67f5c8b2018-09-24 12:09:19 -070024import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
25import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
26import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
Sunny Goyalaac6c882019-02-11 11:57:58 -080027import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_CHANNEL;
28import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
29import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
30import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
Winson Chung67f5c8b2018-09-24 12:09:19 -070031
Matthew Ng30c0a022017-11-10 14:06:29 -080032import android.content.BroadcastReceiver;
Matthew Ng13dbf872017-10-27 11:02:14 -070033import android.content.ComponentName;
34import android.content.Context;
35import android.content.Intent;
Matthew Ng30c0a022017-11-10 14:06:29 -080036import android.content.IntentFilter;
Matthew Ng13dbf872017-10-27 11:02:14 -070037import android.content.ServiceConnection;
Winson Chung38d31c22017-11-08 14:32:32 -080038import android.graphics.Rect;
Sunny Goyalaac6c882019-02-11 11:57:58 -080039import android.graphics.Region;
Winson Chung38d31c22017-11-08 14:32:32 -080040import android.os.Binder;
Sunny Goyalaac6c882019-02-11 11:57:58 -080041import android.os.Bundle;
Matthew Ng13dbf872017-10-27 11:02:14 -070042import android.os.Handler;
43import android.os.IBinder;
Matthew Ngfac87832017-11-10 11:27:29 -080044import android.os.Looper;
Matthew Ng30c0a022017-11-10 14:06:29 -080045import android.os.PatternMatcher;
Matthew Ng13dbf872017-10-27 11:02:14 -070046import android.os.RemoteException;
47import android.os.UserHandle;
Winson Chung387e38b2018-07-09 14:30:54 -070048import android.provider.Settings;
Matthew Ng13dbf872017-10-27 11:02:14 -070049import android.util.Log;
Sunny Goyalaac6c882019-02-11 11:57:58 -080050import android.view.InputChannel;
Hyunyoung Songc1647ea2018-08-20 12:23:46 -070051import android.view.MotionEvent;
Gus Prevasab336792018-11-14 13:52:20 -050052
Lucas Dupin086c6fc2018-10-16 18:06:43 -070053import com.android.internal.policy.ScreenDecorationsUtils;
Winson Chung2dbcf092018-10-24 13:00:41 -070054import com.android.systemui.Dumpable;
55import com.android.systemui.Prefs;
56import com.android.systemui.SysUiServiceProvider;
57import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
Winson Chung38d31c22017-11-08 14:32:32 -080058import com.android.systemui.shared.recents.IOverviewProxy;
59import com.android.systemui.shared.recents.ISystemUiProxy;
Winson Chungd95a2252018-04-04 17:02:29 +000060import com.android.systemui.shared.system.ActivityManagerWrapper;
Sunny Goyalaac6c882019-02-11 11:57:58 -080061import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
Matthew Ngc603a502018-04-18 17:14:22 -070062import com.android.systemui.stackdivider.Divider;
Winson Chungcaf2b812018-01-26 10:29:46 -080063import com.android.systemui.statusbar.phone.StatusBar;
Matthew Ng7d05e772017-11-09 14:41:07 -080064import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070065import com.android.systemui.statusbar.policy.DeviceProvisionedController;
66import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Gus Prevasab336792018-11-14 13:52:20 -050067
Matthew Ng1e43ebd2017-11-14 14:47:05 -080068import java.io.FileDescriptor;
69import java.io.PrintWriter;
Matthew Ng7d05e772017-11-09 14:41:07 -080070import java.util.ArrayList;
71import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070072
Jason Monk196d6392018-12-20 13:25:34 -050073import javax.inject.Inject;
74import javax.inject.Singleton;
75
Matthew Ng13dbf872017-10-27 11:02:14 -070076/**
77 * Class to send information from overview to launcher with a binder.
78 */
Jason Monk196d6392018-12-20 13:25:34 -050079@Singleton
Matthew Ng1e43ebd2017-11-14 14:47:05 -080080public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
Matthew Ng13dbf872017-10-27 11:02:14 -070081
Sunny Goyal09c12d72018-03-27 10:14:49 -070082 private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
83
Matthew Ngbd824572018-01-17 16:25:56 -080084 public static final String TAG_OPS = "OverviewProxyService";
85 public static final boolean DEBUG_OVERVIEW_PROXY = false;
Matthew Ng96087482018-06-27 15:32:09 -070086 private static final long BACKOFF_MILLIS = 1000;
Matthew Nge3c5af42018-05-02 16:58:44 -070087 private static final long DEFERRED_CALLBACK_MILLIS = 5000;
Matthew Ng13dbf872017-10-27 11:02:14 -070088
Matthew Ngead8e5a2018-08-20 17:20:05 -070089 // Max backoff caps at 5 mins
90 private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
91
Matthew Ng0769e442018-08-06 15:05:33 -070092 // Default interaction flags if swipe up is disabled before connecting to launcher
93 private static final int DEFAULT_DISABLE_SWIPE_UP_STATE = FLAG_DISABLE_SWIPE_UP
94 | FLAG_SHOW_OVERVIEW_BUTTON;
95
Matthew Ng13dbf872017-10-27 11:02:14 -070096 private final Context mContext;
97 private final Handler mHandler;
Matthew Ngfac87832017-11-10 11:27:29 -080098 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
Sunny Goyal09c12d72018-03-27 10:14:49 -070099 private final ComponentName mRecentsComponentName;
Jason Monk96a37f42018-12-21 14:45:26 -0500100 private final DeviceProvisionedController mDeviceProvisionedController;
Matthew Ng7d05e772017-11-09 14:41:07 -0800101 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Winson Chungd95a2252018-04-04 17:02:29 +0000102 private final Intent mQuickStepIntent;
Matthew Ng13dbf872017-10-27 11:02:14 -0700103
Sunny Goyalaac6c882019-02-11 11:57:58 -0800104 private Region mActiveNavBarRegion;
105
Matthew Ng13dbf872017-10-27 11:02:14 -0700106 private IOverviewProxy mOverviewProxy;
107 private int mConnectionBackoffAttempts;
Matthew Ng8f25fb962018-01-16 17:17:24 -0800108 private @InteractionType int mInteractionFlags;
Winson Chungd95a2252018-04-04 17:02:29 +0000109 private boolean mIsEnabled;
Matthew Ngffb17372018-07-18 12:31:29 -0700110 private int mCurrentBoundedUserId = -1;
Matthew Ngc83b9892018-08-21 16:31:13 -0700111 private float mBackButtonAlpha;
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700112 private MotionEvent mStatusBarGestureDownEvent;
Lucas Dupin086c6fc2018-10-16 18:06:43 -0700113 private float mWindowCornerRadius;
Lucas Dupinf36d0dc2019-01-09 09:07:50 -0800114 private boolean mSupportsRoundedCornersOnWindows;
Matthew Ng13dbf872017-10-27 11:02:14 -0700115
Sunny Goyalaac6c882019-02-11 11:57:58 -0800116 private InputEventDispatcher mInputEventDispatcher;
117
Winson Chung38d31c22017-11-08 14:32:32 -0800118 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
Winson Chungcaf2b812018-01-26 10:29:46 -0800119
Winson Chungcaf2b812018-01-26 10:29:46 -0800120 public void startScreenPinning(int taskId) {
Matthew Ngffb17372018-07-18 12:31:29 -0700121 if (!verifyCaller("startScreenPinning")) {
122 return;
123 }
Winson Chungcaf2b812018-01-26 10:29:46 -0800124 long token = Binder.clearCallingIdentity();
125 try {
126 mHandler.post(() -> {
Winson Chung06ca2742018-06-29 12:26:49 -0700127 StatusBar statusBar = SysUiServiceProvider.getComponent(mContext,
Winson Chungcaf2b812018-01-26 10:29:46 -0800128 StatusBar.class);
129 if (statusBar != null) {
130 statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
131 }
132 });
133 } finally {
134 Binder.restoreCallingIdentity(token);
135 }
136 }
137
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700138 public void onStatusBarMotionEvent(MotionEvent event) {
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700139 if (!verifyCaller("onStatusBarMotionEvent")) {
140 return;
141 }
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700142 long token = Binder.clearCallingIdentity();
143 try {
144 // TODO move this logic to message queue
145 mHandler.post(()->{
146 StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
147 if (bar != null) {
148 bar.dispatchNotificationsPanelTouchEvent(event);
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700149
150 int action = event.getActionMasked();
151 if (action == ACTION_DOWN) {
152 mStatusBarGestureDownEvent = MotionEvent.obtain(event);
153 }
154 if (action == ACTION_UP || action == ACTION_CANCEL) {
155 mStatusBarGestureDownEvent.recycle();
156 mStatusBarGestureDownEvent = null;
157 }
158 event.recycle();
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700159 }
160 });
161 } finally {
162 Binder.restoreCallingIdentity(token);
163 }
164 }
165
Winson Chungc1674272018-02-21 10:15:17 -0800166 public void onSplitScreenInvoked() {
Matthew Ngffb17372018-07-18 12:31:29 -0700167 if (!verifyCaller("onSplitScreenInvoked")) {
168 return;
169 }
Winson Chungc1674272018-02-21 10:15:17 -0800170 long token = Binder.clearCallingIdentity();
171 try {
Winson Chung67f5c8b2018-09-24 12:09:19 -0700172 Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class);
173 if (divider != null) {
174 divider.onDockedFirstAnimationFrame();
175 }
Winson Chungc1674272018-02-21 10:15:17 -0800176 } finally {
177 Binder.restoreCallingIdentity(token);
178 }
179 }
180
Tracy Zhou27599052018-04-16 15:47:29 -0700181 public void onOverviewShown(boolean fromHome) {
Matthew Ngffb17372018-07-18 12:31:29 -0700182 if (!verifyCaller("onOverviewShown")) {
183 return;
184 }
Tracy Zhou27599052018-04-16 15:47:29 -0700185 long token = Binder.clearCallingIdentity();
186 try {
187 mHandler.post(() -> {
188 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
189 mConnectionCallbacks.get(i).onOverviewShown(fromHome);
190 }
191 });
192 } finally {
193 Binder.restoreCallingIdentity(token);
194 }
195 }
196
Matthew Ng8f25fb962018-01-16 17:17:24 -0800197 public void setInteractionState(@InteractionType int flags) {
Matthew Ngffb17372018-07-18 12:31:29 -0700198 if (!verifyCaller("setInteractionState")) {
199 return;
200 }
Matthew Ng8f25fb962018-01-16 17:17:24 -0800201 long token = Binder.clearCallingIdentity();
202 try {
203 if (mInteractionFlags != flags) {
204 mInteractionFlags = flags;
205 mHandler.post(() -> {
206 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
207 mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
208 }
209 });
210 }
211 } finally {
Winson Chungd95a2252018-04-04 17:02:29 +0000212 Prefs.putInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, mInteractionFlags);
Matthew Ng8f25fb962018-01-16 17:17:24 -0800213 Binder.restoreCallingIdentity(token);
214 }
215 }
Matthew Ngc603a502018-04-18 17:14:22 -0700216
217 public Rect getNonMinimizedSplitScreenSecondaryBounds() {
Matthew Ngffb17372018-07-18 12:31:29 -0700218 if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) {
219 return null;
220 }
Matthew Ngc603a502018-04-18 17:14:22 -0700221 long token = Binder.clearCallingIdentity();
222 try {
Winson Chung06ca2742018-06-29 12:26:49 -0700223 Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class);
Matthew Ngc603a502018-04-18 17:14:22 -0700224 if (divider != null) {
225 return divider.getView().getNonMinimizedSplitScreenSecondaryBounds();
226 }
227 return null;
228 } finally {
229 Binder.restoreCallingIdentity(token);
230 }
231 }
Matthew Ng96985e72018-05-08 15:46:13 -0700232
233 public void setBackButtonAlpha(float alpha, boolean animate) {
Matthew Ngffb17372018-07-18 12:31:29 -0700234 if (!verifyCaller("setBackButtonAlpha")) {
235 return;
236 }
Matthew Ng96985e72018-05-08 15:46:13 -0700237 long token = Binder.clearCallingIdentity();
238 try {
Matthew Ngc83b9892018-08-21 16:31:13 -0700239 mBackButtonAlpha = alpha;
Matthew Ng96985e72018-05-08 15:46:13 -0700240 mHandler.post(() -> {
Matthew Ng53896452018-05-30 11:27:39 -0700241 notifyBackButtonAlphaChanged(alpha, animate);
Matthew Ng96985e72018-05-08 15:46:13 -0700242 });
243 } finally {
244 Binder.restoreCallingIdentity(token);
245 }
246 }
Matthew Ngffb17372018-07-18 12:31:29 -0700247
Lucas Dupin086c6fc2018-10-16 18:06:43 -0700248 public float getWindowCornerRadius() {
249 if (!verifyCaller("getWindowCornerRadius")) {
250 return 0;
251 }
252 long token = Binder.clearCallingIdentity();
253 try {
254 return mWindowCornerRadius;
255 } finally {
256 Binder.restoreCallingIdentity(token);
257 }
258 }
259
Lucas Dupinf36d0dc2019-01-09 09:07:50 -0800260 public boolean supportsRoundedCornersOnWindows() {
261 if (!verifyCaller("supportsRoundedCornersOnWindows")) {
262 return false;
263 }
264 long token = Binder.clearCallingIdentity();
265 try {
266 return mSupportsRoundedCornersOnWindows;
267 } finally {
268 Binder.restoreCallingIdentity(token);
269 }
270 }
271
Matthew Ngffb17372018-07-18 12:31:29 -0700272 private boolean verifyCaller(String reason) {
273 final int callerId = Binder.getCallingUserHandle().getIdentifier();
274 if (callerId != mCurrentBoundedUserId) {
275 Log.w(TAG_OPS, "Launcher called sysui with invalid user: " + callerId + ", reason: "
276 + reason);
277 return false;
278 }
279 return true;
280 }
Winson Chung38d31c22017-11-08 14:32:32 -0800281 };
282
Matthew Nge3c5af42018-05-02 16:58:44 -0700283 private final Runnable mDeferredConnectionCallback = () -> {
284 Log.w(TAG_OPS, "Binder supposed established connection but actual connection to service "
285 + "timed out, trying again");
Matthew Ngead8e5a2018-08-20 17:20:05 -0700286 retryConnectionWithBackoff();
Matthew Nge3c5af42018-05-02 16:58:44 -0700287 };
288
Winson Chungd95a2252018-04-04 17:02:29 +0000289 private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
Matthew Ng30c0a022017-11-10 14:06:29 -0800290 @Override
291 public void onReceive(Context context, Intent intent) {
Winson Chungd95a2252018-04-04 17:02:29 +0000292 updateEnabledState();
293
294 // When launcher service is disabled, reset interaction flags because it is inactive
295 if (!isEnabled()) {
Matthew Ng0769e442018-08-06 15:05:33 -0700296 mInteractionFlags = getDefaultInteractionFlags();
Winson Chungd95a2252018-04-04 17:02:29 +0000297 Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS);
298 }
299
Matthew Ng30c0a022017-11-10 14:06:29 -0800300 // Reconnect immediately, instead of waiting for resume to arrive.
301 startConnectionToCurrentUser();
302 }
303 };
304
Matthew Ng13dbf872017-10-27 11:02:14 -0700305 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
306 @Override
307 public void onServiceConnected(ComponentName name, IBinder service) {
Matthew Nge3c5af42018-05-02 16:58:44 -0700308 mHandler.removeCallbacks(mDeferredConnectionCallback);
Matthew Ng4c3973d2018-10-15 17:21:24 -0700309 mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
Matthew Nge3c5af42018-05-02 16:58:44 -0700310 mConnectionBackoffAttempts = 0;
311 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
312 // Listen for launcher's death
313 try {
314 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
315 } catch (RemoteException e) {
316 Log.e(TAG_OPS, "Lost connection to launcher service", e);
Matthew Ng13dbf872017-10-27 11:02:14 -0700317 }
Matthew Nge3c5af42018-05-02 16:58:44 -0700318 try {
319 mOverviewProxy.onBind(mSysUiProxy);
320 } catch (RemoteException e) {
Matthew Ngffb17372018-07-18 12:31:29 -0700321 mCurrentBoundedUserId = -1;
Matthew Nge3c5af42018-05-02 16:58:44 -0700322 Log.e(TAG_OPS, "Failed to call onBind()", e);
323 }
Sunny Goyalaac6c882019-02-11 11:57:58 -0800324
325 Bundle params = new Bundle();
326 params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
327 params.putParcelable(KEY_EXTRA_INPUT_CHANNEL, createNewInputDispatcher());
328 params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
329 params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
330 try {
331 mOverviewProxy.onInitialize(params);
332 } catch (RemoteException e) {
333 // Ignore error until the migration is complete.
334 Log.e(TAG_OPS, "Failed to call onBind()", e);
335 }
336 dispatchNavButtonBounds();
337
Matthew Nge3c5af42018-05-02 16:58:44 -0700338 notifyConnectionChanged();
339 }
340
341 @Override
342 public void onNullBinding(ComponentName name) {
343 Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting");
Matthew Ngffb17372018-07-18 12:31:29 -0700344 mCurrentBoundedUserId = -1;
Matthew Ngead8e5a2018-08-20 17:20:05 -0700345 retryConnectionWithBackoff();
Sunny Goyalaac6c882019-02-11 11:57:58 -0800346 disposeInputDispatcher();
Matthew Nge3c5af42018-05-02 16:58:44 -0700347 }
348
349 @Override
350 public void onBindingDied(ComponentName name) {
351 Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting");
Matthew Ngffb17372018-07-18 12:31:29 -0700352 mCurrentBoundedUserId = -1;
Matthew Ngead8e5a2018-08-20 17:20:05 -0700353 retryConnectionWithBackoff();
Sunny Goyalaac6c882019-02-11 11:57:58 -0800354 disposeInputDispatcher();
Matthew Ng13dbf872017-10-27 11:02:14 -0700355 }
356
357 @Override
358 public void onServiceDisconnected(ComponentName name) {
359 // Do nothing
Matthew Ngffb17372018-07-18 12:31:29 -0700360 mCurrentBoundedUserId = -1;
Sunny Goyalaac6c882019-02-11 11:57:58 -0800361 disposeInputDispatcher();
Matthew Ng13dbf872017-10-27 11:02:14 -0700362 }
363 };
364
Sunny Goyalaac6c882019-02-11 11:57:58 -0800365 private void disposeInputDispatcher() {
366 if (mInputEventDispatcher != null) {
367 mInputEventDispatcher.dispose();
368 mInputEventDispatcher = null;
369 }
370 }
371
372 private InputChannel createNewInputDispatcher() {
373 disposeInputDispatcher();
374
375 InputChannel[] channels = InputChannel.openInputChannelPair("overview-proxy-service");
376 mInputEventDispatcher = new InputEventDispatcher(channels[0], Looper.getMainLooper());
377 return channels[1];
378 }
379
Matthew Ng13dbf872017-10-27 11:02:14 -0700380 private final DeviceProvisionedListener mDeviceProvisionedCallback =
381 new DeviceProvisionedListener() {
382 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800383 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700384 if (mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ngfac87832017-11-10 11:27:29 -0800385 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700386 }
387 }
388
389 @Override
390 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700391 mConnectionBackoffAttempts = 0;
Matthew Ngfac87832017-11-10 11:27:29 -0800392 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700393 }
394 };
395
396 // This is the death handler for the binder from the launcher service
Matthew Ng30c0a022017-11-10 14:06:29 -0800397 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700398 = this::cleanupAfterDeath;
Matthew Ng13dbf872017-10-27 11:02:14 -0700399
Jason Monk196d6392018-12-20 13:25:34 -0500400 @Inject
Jason Monk96a37f42018-12-21 14:45:26 -0500401 public OverviewProxyService(Context context, DeviceProvisionedController provisionController) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700402 mContext = context;
403 mHandler = new Handler();
Jason Monk96a37f42018-12-21 14:45:26 -0500404 mDeviceProvisionedController = provisionController;
Matthew Ng13dbf872017-10-27 11:02:14 -0700405 mConnectionBackoffAttempts = 0;
Sunny Goyal09c12d72018-03-27 10:14:49 -0700406 mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
407 com.android.internal.R.string.config_recentsComponentName));
Winson Chungd95a2252018-04-04 17:02:29 +0000408 mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
409 .setPackage(mRecentsComponentName.getPackageName());
Matthew Ng0769e442018-08-06 15:05:33 -0700410 mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS,
411 getDefaultInteractionFlags());
Lucas Dupin086c6fc2018-10-16 18:06:43 -0700412 mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources());
Lucas Dupinf36d0dc2019-01-09 09:07:50 -0800413 mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
414 .supportsRoundedCornersOnWindows(mContext.getResources());
Matthew Ng30c0a022017-11-10 14:06:29 -0800415
416 // Listen for the package update changes.
Winson Chung67f5c8b2018-09-24 12:09:19 -0700417 if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
Winson Chungd95a2252018-04-04 17:02:29 +0000418 updateEnabledState();
Matthew Ng1b1d3462018-03-02 11:43:38 -0800419 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
420 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
421 filter.addDataScheme("package");
Sunny Goyal09c12d72018-03-27 10:14:49 -0700422 filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
Matthew Ng1b1d3462018-03-02 11:43:38 -0800423 PatternMatcher.PATTERN_LITERAL);
424 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Winson Chungd95a2252018-04-04 17:02:29 +0000425 mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
Matthew Ng1b1d3462018-03-02 11:43:38 -0800426 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700427 }
428
Sunny Goyalaac6c882019-02-11 11:57:58 -0800429 /**
430 * Sets the navbar region which can receive touch inputs
431 */
432 public void onActiveNavBarRegionChanges(Region activeRegion) {
433 mActiveNavBarRegion = activeRegion;
434 dispatchNavButtonBounds();
435 }
436
437 private void dispatchNavButtonBounds() {
438 if (mOverviewProxy != null && mActiveNavBarRegion != null) {
439 try {
440 mOverviewProxy.onActiveNavBarRegionChanges(mActiveNavBarRegion);
441 } catch (RemoteException e) {
442 Log.e(TAG_OPS, "Failed to call onActiveNavBarRegionChanges()", e);
443 }
444 }
445 }
446
Matthew Ngc83b9892018-08-21 16:31:13 -0700447 public float getBackButtonAlpha() {
448 return mBackButtonAlpha;
449 }
450
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700451 public void cleanupAfterDeath() {
452 if (mStatusBarGestureDownEvent != null) {
453 mHandler.post(()-> {
454 StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
455 if (bar != null) {
456 System.out.println("MERONG dispatchNotificationPanelTouchEvent");
457 mStatusBarGestureDownEvent.setAction(MotionEvent.ACTION_CANCEL);
458 bar.dispatchNotificationsPanelTouchEvent(mStatusBarGestureDownEvent);
459 mStatusBarGestureDownEvent.recycle();
460 mStatusBarGestureDownEvent = null;
461 }
462 });
463 }
464 startConnectionToCurrentUser();
465 }
466
Matthew Ng13dbf872017-10-27 11:02:14 -0700467 public void startConnectionToCurrentUser() {
Matthew Ngfac87832017-11-10 11:27:29 -0800468 if (mHandler.getLooper() != Looper.myLooper()) {
469 mHandler.post(mConnectionRunnable);
470 } else {
471 internalConnectToCurrentUser();
472 }
473 }
474
475 private void internalConnectToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800476 disconnectFromLauncherService();
477
Matthew Ng13dbf872017-10-27 11:02:14 -0700478 // If user has not setup yet or already connected, do not try to connect
Winson Chungd95a2252018-04-04 17:02:29 +0000479 if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
Matthew Nge3c5af42018-05-02 16:58:44 -0700480 Log.v(TAG_OPS, "Cannot attempt connection, is setup "
481 + mDeviceProvisionedController.isCurrentUserSetup() + ", is enabled "
482 + isEnabled());
Matthew Ng13dbf872017-10-27 11:02:14 -0700483 return;
484 }
485 mHandler.removeCallbacks(mConnectionRunnable);
Sunny Goyal09c12d72018-03-27 10:14:49 -0700486 Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
487 .setPackage(mRecentsComponentName.getPackageName());
Matthew Ng10b6c41a2018-03-26 18:01:37 -0700488 boolean bound = false;
489 try {
490 bound = mContext.bindServiceAsUser(launcherServiceIntent,
Winson Chunge7cb0c12018-07-30 16:11:38 -0700491 mOverviewServiceConnection,
492 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
Matthew Ng10b6c41a2018-03-26 18:01:37 -0700493 UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
494 } catch (SecurityException e) {
495 Log.e(TAG_OPS, "Unable to bind because of security error", e);
496 }
Matthew Nge3c5af42018-05-02 16:58:44 -0700497 if (bound) {
498 // Ensure that connection has been established even if it thinks it is bound
499 mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
500 } else {
Matthew Ng13dbf872017-10-27 11:02:14 -0700501 // Retry after exponential backoff timeout
Matthew Ngead8e5a2018-08-20 17:20:05 -0700502 retryConnectionWithBackoff();
Matthew Ng13dbf872017-10-27 11:02:14 -0700503 }
504 }
505
Matthew Ngead8e5a2018-08-20 17:20:05 -0700506 private void retryConnectionWithBackoff() {
507 if (mHandler.hasCallbacks(mConnectionRunnable)) {
508 return;
509 }
510 final long timeoutMs = (long) Math.min(
511 Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts), MAX_BACKOFF_MILLIS);
512 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
513 mConnectionBackoffAttempts++;
514 Log.w(TAG_OPS, "Failed to connect on attempt " + mConnectionBackoffAttempts
515 + " will try again in " + timeoutMs + "ms");
516 }
517
Matthew Ng7d05e772017-11-09 14:41:07 -0800518 @Override
519 public void addCallback(OverviewProxyListener listener) {
520 mConnectionCallbacks.add(listener);
521 listener.onConnectionChanged(mOverviewProxy != null);
Winson Chungd95a2252018-04-04 17:02:29 +0000522 listener.onInteractionFlagsChanged(mInteractionFlags);
Matthew Ng7d05e772017-11-09 14:41:07 -0800523 }
524
525 @Override
526 public void removeCallback(OverviewProxyListener listener) {
527 mConnectionCallbacks.remove(listener);
528 }
529
Matthew Ngc1a97b12018-03-28 14:02:00 -0700530 public boolean shouldShowSwipeUpUI() {
Winson Chungd95a2252018-04-04 17:02:29 +0000531 return isEnabled() && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
532 }
533
534 public boolean isEnabled() {
535 return mIsEnabled;
Matthew Ngc1a97b12018-03-28 14:02:00 -0700536 }
537
Matthew Ng13dbf872017-10-27 11:02:14 -0700538 public IOverviewProxy getProxy() {
539 return mOverviewProxy;
540 }
541
Sunny Goyalaac6c882019-02-11 11:57:58 -0800542 public InputEventDispatcher getInputEventDispatcher() {
543 return mInputEventDispatcher;
544 }
545
Matthew Ng8f25fb962018-01-16 17:17:24 -0800546 public int getInteractionFlags() {
547 return mInteractionFlags;
548 }
549
Matthew Ng13dbf872017-10-27 11:02:14 -0700550 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800551 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800552 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800553 mContext.unbindService(mOverviewServiceConnection);
554 mOverviewProxy = null;
Matthew Ng53896452018-05-30 11:27:39 -0700555 notifyBackButtonAlphaChanged(1f, false /* animate */);
Matthew Ng7d05e772017-11-09 14:41:07 -0800556 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800557 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700558 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800559
Matthew Ng0769e442018-08-06 15:05:33 -0700560 private int getDefaultInteractionFlags() {
561 // If there is no settings available use device default or get it from settings
562 final boolean defaultState = getSwipeUpDefaultValue();
563 final boolean swipeUpEnabled = getSwipeUpSettingAvailable()
564 ? getSwipeUpEnabledFromSettings(defaultState)
565 : defaultState;
566 return swipeUpEnabled ? 0 : DEFAULT_DISABLE_SWIPE_UP_STATE;
567 }
568
Matthew Ng53896452018-05-30 11:27:39 -0700569 private void notifyBackButtonAlphaChanged(float alpha, boolean animate) {
570 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
571 mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate);
572 }
573 }
574
Matthew Ng7d05e772017-11-09 14:41:07 -0800575 private void notifyConnectionChanged() {
576 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
577 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
578 }
579 }
580
Matthew Ng2ea93b72018-03-14 19:43:18 +0000581 public void notifyQuickStepStarted() {
Winson Chungcbb15a92018-01-25 17:46:16 +0000582 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000583 mConnectionCallbacks.get(i).onQuickStepStarted();
Winson Chungcbb15a92018-01-25 17:46:16 +0000584 }
585 }
586
Tracy Zhou27599052018-04-16 15:47:29 -0700587 public void notifyQuickScrubStarted() {
588 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
589 mConnectionCallbacks.get(i).onQuickScrubStarted();
590 }
591 }
592
Winson Chungd95a2252018-04-04 17:02:29 +0000593 private void updateEnabledState() {
Winson Chung6e4b0b562018-04-04 09:13:37 -0700594 mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
595 MATCH_DIRECT_BOOT_UNAWARE,
Winson Chungd95a2252018-04-04 17:02:29 +0000596 ActivityManagerWrapper.getInstance().getCurrentUserId()) != null;
597 }
598
Matthew Ng0769e442018-08-06 15:05:33 -0700599 private boolean getSwipeUpDefaultValue() {
600 return mContext.getResources()
601 .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_default);
602 }
603
604 private boolean getSwipeUpSettingAvailable() {
605 return mContext.getResources()
606 .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_setting_available);
607 }
608
609 private boolean getSwipeUpEnabledFromSettings(boolean defaultValue) {
610 return Settings.Secure.getInt(mContext.getContentResolver(),
611 Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED, defaultValue ? 1 : 0) == 1;
612 }
613
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800614 @Override
615 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Matthew Ngbd824572018-01-17 16:25:56 -0800616 pw.println(TAG_OPS + " state:");
Winson Chung387e38b2018-07-09 14:30:54 -0700617 pw.print(" recentsComponentName="); pw.println(mRecentsComponentName);
618 pw.print(" isConnected="); pw.println(mOverviewProxy != null);
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800619 pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
620 .isCurrentUserSetup());
Winson Chung387e38b2018-07-09 14:30:54 -0700621 pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
622 pw.print(" interactionFlags="); pw.println(mInteractionFlags);
623
624 pw.print(" quickStepIntent="); pw.println(mQuickStepIntent);
625 pw.print(" quickStepIntentResolved="); pw.println(isEnabled());
626
Matthew Ng0769e442018-08-06 15:05:33 -0700627 final boolean swipeUpDefaultValue = getSwipeUpDefaultValue();
628 final boolean swipeUpEnabled = getSwipeUpEnabledFromSettings(swipeUpDefaultValue);
629 pw.print(" swipeUpSetting="); pw.println(swipeUpEnabled);
630 pw.print(" swipeUpSettingDefault="); pw.println(swipeUpDefaultValue);
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800631 }
632
Matthew Ng7d05e772017-11-09 14:41:07 -0800633 public interface OverviewProxyListener {
Winson Chungcbb15a92018-01-25 17:46:16 +0000634 default void onConnectionChanged(boolean isConnected) {}
Matthew Ng2ea93b72018-03-14 19:43:18 +0000635 default void onQuickStepStarted() {}
Matthew Ng8f25fb962018-01-16 17:17:24 -0800636 default void onInteractionFlagsChanged(@InteractionType int flags) {}
Tracy Zhou27599052018-04-16 15:47:29 -0700637 default void onOverviewShown(boolean fromHome) {}
638 default void onQuickScrubStarted() {}
Matthew Ng96985e72018-05-08 15:46:13 -0700639 default void onBackButtonAlphaChanged(float alpha, boolean animate) {}
Matthew Ng7d05e772017-11-09 14:41:07 -0800640 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700641}