blob: 4da8ca28f4c7c1318457ed862dc8d7a55f35770d [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
Matthew Nga3fee342019-02-25 15:36:37 -080019import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
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 Ng42025e32019-02-20 15:02:58 -080032import android.annotation.FloatRange;
Matthew Ng30c0a022017-11-10 14:06:29 -080033import android.content.BroadcastReceiver;
Matthew Ng13dbf872017-10-27 11:02:14 -070034import android.content.ComponentName;
35import android.content.Context;
36import android.content.Intent;
Matthew Ng30c0a022017-11-10 14:06:29 -080037import android.content.IntentFilter;
Matthew Ng13dbf872017-10-27 11:02:14 -070038import android.content.ServiceConnection;
Winson Chung38d31c22017-11-08 14:32:32 -080039import android.graphics.Rect;
Sunny Goyalaac6c882019-02-11 11:57:58 -080040import android.graphics.Region;
Winson Chung38d31c22017-11-08 14:32:32 -080041import android.os.Binder;
Sunny Goyalaac6c882019-02-11 11:57:58 -080042import android.os.Bundle;
Matthew Ng13dbf872017-10-27 11:02:14 -070043import android.os.Handler;
44import android.os.IBinder;
Matthew Ngfac87832017-11-10 11:27:29 -080045import android.os.Looper;
Matthew Ng30c0a022017-11-10 14:06:29 -080046import android.os.PatternMatcher;
Matthew Ng13dbf872017-10-27 11:02:14 -070047import android.os.RemoteException;
48import android.os.UserHandle;
Winson Chung387e38b2018-07-09 14:30:54 -070049import android.provider.Settings;
Matthew Ng13dbf872017-10-27 11:02:14 -070050import android.util.Log;
Sunny Goyalaac6c882019-02-11 11:57:58 -080051import android.view.InputChannel;
Hyunyoung Songc1647ea2018-08-20 12:23:46 -070052import android.view.MotionEvent;
Gus Prevasab336792018-11-14 13:52:20 -050053
Lucas Dupin086c6fc2018-10-16 18:06:43 -070054import com.android.internal.policy.ScreenDecorationsUtils;
Winson Chung2dbcf092018-10-24 13:00:41 -070055import com.android.systemui.Dumpable;
56import com.android.systemui.Prefs;
57import com.android.systemui.SysUiServiceProvider;
58import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
Winson Chung38d31c22017-11-08 14:32:32 -080059import com.android.systemui.shared.recents.IOverviewProxy;
60import com.android.systemui.shared.recents.ISystemUiProxy;
Winson Chungd95a2252018-04-04 17:02:29 +000061import com.android.systemui.shared.system.ActivityManagerWrapper;
Sunny Goyalaac6c882019-02-11 11:57:58 -080062import com.android.systemui.shared.system.InputChannelCompat.InputEventDispatcher;
Matthew Ngc603a502018-04-18 17:14:22 -070063import com.android.systemui.stackdivider.Divider;
Winson Chungcaf2b812018-01-26 10:29:46 -080064import com.android.systemui.statusbar.phone.StatusBar;
Matthew Ng7d05e772017-11-09 14:41:07 -080065import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070066import com.android.systemui.statusbar.policy.DeviceProvisionedController;
67import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Gus Prevasab336792018-11-14 13:52:20 -050068
Matthew Ng1e43ebd2017-11-14 14:47:05 -080069import java.io.FileDescriptor;
70import java.io.PrintWriter;
Matthew Ng7d05e772017-11-09 14:41:07 -080071import java.util.ArrayList;
72import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070073
Jason Monk196d6392018-12-20 13:25:34 -050074import javax.inject.Inject;
75import javax.inject.Singleton;
76
Matthew Ng13dbf872017-10-27 11:02:14 -070077/**
78 * Class to send information from overview to launcher with a binder.
79 */
Jason Monk196d6392018-12-20 13:25:34 -050080@Singleton
Matthew Ng1e43ebd2017-11-14 14:47:05 -080081public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
Matthew Ng13dbf872017-10-27 11:02:14 -070082
Sunny Goyal09c12d72018-03-27 10:14:49 -070083 private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
84
Matthew Ngbd824572018-01-17 16:25:56 -080085 public static final String TAG_OPS = "OverviewProxyService";
86 public static final boolean DEBUG_OVERVIEW_PROXY = false;
Matthew Ng96087482018-06-27 15:32:09 -070087 private static final long BACKOFF_MILLIS = 1000;
Matthew Nge3c5af42018-05-02 16:58:44 -070088 private static final long DEFERRED_CALLBACK_MILLIS = 5000;
Matthew Ng13dbf872017-10-27 11:02:14 -070089
Matthew Ngead8e5a2018-08-20 17:20:05 -070090 // Max backoff caps at 5 mins
91 private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
92
Matthew Ng0769e442018-08-06 15:05:33 -070093 // Default interaction flags if swipe up is disabled before connecting to launcher
94 private static final int DEFAULT_DISABLE_SWIPE_UP_STATE = FLAG_DISABLE_SWIPE_UP
95 | FLAG_SHOW_OVERVIEW_BUTTON;
96
Matthew Ng13dbf872017-10-27 11:02:14 -070097 private final Context mContext;
98 private final Handler mHandler;
Matthew Ngfac87832017-11-10 11:27:29 -080099 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
Sunny Goyal09c12d72018-03-27 10:14:49 -0700100 private final ComponentName mRecentsComponentName;
Jason Monk96a37f42018-12-21 14:45:26 -0500101 private final DeviceProvisionedController mDeviceProvisionedController;
Matthew Ng7d05e772017-11-09 14:41:07 -0800102 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Winson Chungd95a2252018-04-04 17:02:29 +0000103 private final Intent mQuickStepIntent;
Matthew Ng13dbf872017-10-27 11:02:14 -0700104
Sunny Goyalaac6c882019-02-11 11:57:58 -0800105 private Region mActiveNavBarRegion;
106
Matthew Ng13dbf872017-10-27 11:02:14 -0700107 private IOverviewProxy mOverviewProxy;
108 private int mConnectionBackoffAttempts;
Matthew Ng8f25fb962018-01-16 17:17:24 -0800109 private @InteractionType int mInteractionFlags;
Winson Chungd95a2252018-04-04 17:02:29 +0000110 private boolean mIsEnabled;
Matthew Ngffb17372018-07-18 12:31:29 -0700111 private int mCurrentBoundedUserId = -1;
Matthew Ngc83b9892018-08-21 16:31:13 -0700112 private float mBackButtonAlpha;
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700113 private MotionEvent mStatusBarGestureDownEvent;
Lucas Dupin086c6fc2018-10-16 18:06:43 -0700114 private float mWindowCornerRadius;
Lucas Dupinf36d0dc2019-01-09 09:07:50 -0800115 private boolean mSupportsRoundedCornersOnWindows;
Matthew Ng13dbf872017-10-27 11:02:14 -0700116
Sunny Goyalaac6c882019-02-11 11:57:58 -0800117 private InputEventDispatcher mInputEventDispatcher;
118
Winson Chung38d31c22017-11-08 14:32:32 -0800119 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
Winson Chungcaf2b812018-01-26 10:29:46 -0800120
Winson Chungcaf2b812018-01-26 10:29:46 -0800121 public void startScreenPinning(int taskId) {
Matthew Ngffb17372018-07-18 12:31:29 -0700122 if (!verifyCaller("startScreenPinning")) {
123 return;
124 }
Winson Chungcaf2b812018-01-26 10:29:46 -0800125 long token = Binder.clearCallingIdentity();
126 try {
127 mHandler.post(() -> {
Winson Chung06ca2742018-06-29 12:26:49 -0700128 StatusBar statusBar = SysUiServiceProvider.getComponent(mContext,
Winson Chungcaf2b812018-01-26 10:29:46 -0800129 StatusBar.class);
130 if (statusBar != null) {
131 statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
132 }
133 });
134 } finally {
135 Binder.restoreCallingIdentity(token);
136 }
137 }
138
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700139 public void onStatusBarMotionEvent(MotionEvent event) {
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700140 if (!verifyCaller("onStatusBarMotionEvent")) {
141 return;
142 }
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700143 long token = Binder.clearCallingIdentity();
144 try {
145 // TODO move this logic to message queue
146 mHandler.post(()->{
147 StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
148 if (bar != null) {
149 bar.dispatchNotificationsPanelTouchEvent(event);
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700150
151 int action = event.getActionMasked();
152 if (action == ACTION_DOWN) {
153 mStatusBarGestureDownEvent = MotionEvent.obtain(event);
154 }
155 if (action == ACTION_UP || action == ACTION_CANCEL) {
156 mStatusBarGestureDownEvent.recycle();
157 mStatusBarGestureDownEvent = null;
158 }
159 event.recycle();
Hyunyoung Songc1647ea2018-08-20 12:23:46 -0700160 }
161 });
162 } finally {
163 Binder.restoreCallingIdentity(token);
164 }
165 }
166
Winson Chungc1674272018-02-21 10:15:17 -0800167 public void onSplitScreenInvoked() {
Matthew Ngffb17372018-07-18 12:31:29 -0700168 if (!verifyCaller("onSplitScreenInvoked")) {
169 return;
170 }
Winson Chungc1674272018-02-21 10:15:17 -0800171 long token = Binder.clearCallingIdentity();
172 try {
Winson Chung67f5c8b2018-09-24 12:09:19 -0700173 Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class);
174 if (divider != null) {
175 divider.onDockedFirstAnimationFrame();
176 }
Winson Chungc1674272018-02-21 10:15:17 -0800177 } finally {
178 Binder.restoreCallingIdentity(token);
179 }
180 }
181
Tracy Zhou27599052018-04-16 15:47:29 -0700182 public void onOverviewShown(boolean fromHome) {
Matthew Ngffb17372018-07-18 12:31:29 -0700183 if (!verifyCaller("onOverviewShown")) {
184 return;
185 }
Tracy Zhou27599052018-04-16 15:47:29 -0700186 long token = Binder.clearCallingIdentity();
187 try {
188 mHandler.post(() -> {
189 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
190 mConnectionCallbacks.get(i).onOverviewShown(fromHome);
191 }
192 });
193 } finally {
194 Binder.restoreCallingIdentity(token);
195 }
196 }
197
Matthew Ng8f25fb962018-01-16 17:17:24 -0800198 public void setInteractionState(@InteractionType int flags) {
Matthew Ngffb17372018-07-18 12:31:29 -0700199 if (!verifyCaller("setInteractionState")) {
200 return;
201 }
Matthew Ng8f25fb962018-01-16 17:17:24 -0800202 long token = Binder.clearCallingIdentity();
203 try {
204 if (mInteractionFlags != flags) {
205 mInteractionFlags = flags;
206 mHandler.post(() -> {
207 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
208 mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
209 }
210 });
211 }
212 } finally {
Winson Chungd95a2252018-04-04 17:02:29 +0000213 Prefs.putInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, mInteractionFlags);
Matthew Ng8f25fb962018-01-16 17:17:24 -0800214 Binder.restoreCallingIdentity(token);
215 }
216 }
Matthew Ngc603a502018-04-18 17:14:22 -0700217
218 public Rect getNonMinimizedSplitScreenSecondaryBounds() {
Matthew Ngffb17372018-07-18 12:31:29 -0700219 if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) {
220 return null;
221 }
Matthew Ngc603a502018-04-18 17:14:22 -0700222 long token = Binder.clearCallingIdentity();
223 try {
Winson Chung06ca2742018-06-29 12:26:49 -0700224 Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class);
Matthew Ngc603a502018-04-18 17:14:22 -0700225 if (divider != null) {
226 return divider.getView().getNonMinimizedSplitScreenSecondaryBounds();
227 }
228 return null;
229 } finally {
230 Binder.restoreCallingIdentity(token);
231 }
232 }
Matthew Ng96985e72018-05-08 15:46:13 -0700233
234 public void setBackButtonAlpha(float alpha, boolean animate) {
Matthew Ngffb17372018-07-18 12:31:29 -0700235 if (!verifyCaller("setBackButtonAlpha")) {
236 return;
237 }
Matthew Ng96985e72018-05-08 15:46:13 -0700238 long token = Binder.clearCallingIdentity();
239 try {
Matthew Ngc83b9892018-08-21 16:31:13 -0700240 mBackButtonAlpha = alpha;
Matthew Ng96985e72018-05-08 15:46:13 -0700241 mHandler.post(() -> {
Matthew Ng53896452018-05-30 11:27:39 -0700242 notifyBackButtonAlphaChanged(alpha, animate);
Matthew Ng96985e72018-05-08 15:46:13 -0700243 });
244 } finally {
245 Binder.restoreCallingIdentity(token);
246 }
247 }
Matthew Ngffb17372018-07-18 12:31:29 -0700248
Lucas Dupin086c6fc2018-10-16 18:06:43 -0700249 public float getWindowCornerRadius() {
250 if (!verifyCaller("getWindowCornerRadius")) {
251 return 0;
252 }
253 long token = Binder.clearCallingIdentity();
254 try {
255 return mWindowCornerRadius;
256 } finally {
257 Binder.restoreCallingIdentity(token);
258 }
259 }
260
Lucas Dupinf36d0dc2019-01-09 09:07:50 -0800261 public boolean supportsRoundedCornersOnWindows() {
262 if (!verifyCaller("supportsRoundedCornersOnWindows")) {
263 return false;
264 }
265 long token = Binder.clearCallingIdentity();
266 try {
267 return mSupportsRoundedCornersOnWindows;
268 } finally {
269 Binder.restoreCallingIdentity(token);
270 }
271 }
272
Matthew Ng42025e32019-02-20 15:02:58 -0800273 public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
274 if (!verifyCaller("onAssistantProgress")) {
275 return;
276 }
277 long token = Binder.clearCallingIdentity();
278 try {
279 mHandler.post(() -> notifyAssistantProgress(progress));
280 } finally {
281 Binder.restoreCallingIdentity(token);
282 }
283 }
284
285 public void startAssistant(Bundle bundle) {
286 if (!verifyCaller("startAssistant")) {
287 return;
288 }
289 long token = Binder.clearCallingIdentity();
290 try {
291 mHandler.post(() -> notifyStartAssistant(bundle));
292 } finally {
293 Binder.restoreCallingIdentity(token);
294 }
295 }
296
Matthew Ngffb17372018-07-18 12:31:29 -0700297 private boolean verifyCaller(String reason) {
298 final int callerId = Binder.getCallingUserHandle().getIdentifier();
299 if (callerId != mCurrentBoundedUserId) {
300 Log.w(TAG_OPS, "Launcher called sysui with invalid user: " + callerId + ", reason: "
301 + reason);
302 return false;
303 }
304 return true;
305 }
Winson Chung38d31c22017-11-08 14:32:32 -0800306 };
307
Matthew Nge3c5af42018-05-02 16:58:44 -0700308 private final Runnable mDeferredConnectionCallback = () -> {
309 Log.w(TAG_OPS, "Binder supposed established connection but actual connection to service "
310 + "timed out, trying again");
Matthew Ngead8e5a2018-08-20 17:20:05 -0700311 retryConnectionWithBackoff();
Matthew Nge3c5af42018-05-02 16:58:44 -0700312 };
313
Winson Chungd95a2252018-04-04 17:02:29 +0000314 private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
Matthew Ng30c0a022017-11-10 14:06:29 -0800315 @Override
316 public void onReceive(Context context, Intent intent) {
Winson Chungd95a2252018-04-04 17:02:29 +0000317 updateEnabledState();
318
319 // When launcher service is disabled, reset interaction flags because it is inactive
320 if (!isEnabled()) {
Matthew Ng0769e442018-08-06 15:05:33 -0700321 mInteractionFlags = getDefaultInteractionFlags();
Winson Chungd95a2252018-04-04 17:02:29 +0000322 Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS);
323 }
324
Matthew Ng30c0a022017-11-10 14:06:29 -0800325 // Reconnect immediately, instead of waiting for resume to arrive.
326 startConnectionToCurrentUser();
327 }
328 };
329
Matthew Ng13dbf872017-10-27 11:02:14 -0700330 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
331 @Override
332 public void onServiceConnected(ComponentName name, IBinder service) {
Matthew Nge3c5af42018-05-02 16:58:44 -0700333 mHandler.removeCallbacks(mDeferredConnectionCallback);
Matthew Ng4c3973d2018-10-15 17:21:24 -0700334 mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
Matthew Nge3c5af42018-05-02 16:58:44 -0700335 mConnectionBackoffAttempts = 0;
336 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
337 // Listen for launcher's death
338 try {
339 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
340 } catch (RemoteException e) {
341 Log.e(TAG_OPS, "Lost connection to launcher service", e);
Matthew Ng13dbf872017-10-27 11:02:14 -0700342 }
Matthew Nge3c5af42018-05-02 16:58:44 -0700343 try {
344 mOverviewProxy.onBind(mSysUiProxy);
345 } catch (RemoteException e) {
Matthew Ngffb17372018-07-18 12:31:29 -0700346 mCurrentBoundedUserId = -1;
Matthew Nge3c5af42018-05-02 16:58:44 -0700347 Log.e(TAG_OPS, "Failed to call onBind()", e);
348 }
Sunny Goyalaac6c882019-02-11 11:57:58 -0800349
350 Bundle params = new Bundle();
351 params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
352 params.putParcelable(KEY_EXTRA_INPUT_CHANNEL, createNewInputDispatcher());
353 params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
354 params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
355 try {
356 mOverviewProxy.onInitialize(params);
357 } catch (RemoteException e) {
358 // Ignore error until the migration is complete.
359 Log.e(TAG_OPS, "Failed to call onBind()", e);
360 }
361 dispatchNavButtonBounds();
362
Matthew Nge3c5af42018-05-02 16:58:44 -0700363 notifyConnectionChanged();
364 }
365
366 @Override
367 public void onNullBinding(ComponentName name) {
368 Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting");
Matthew Ngffb17372018-07-18 12:31:29 -0700369 mCurrentBoundedUserId = -1;
Matthew Ngead8e5a2018-08-20 17:20:05 -0700370 retryConnectionWithBackoff();
Sunny Goyalaac6c882019-02-11 11:57:58 -0800371 disposeInputDispatcher();
Matthew Nge3c5af42018-05-02 16:58:44 -0700372 }
373
374 @Override
375 public void onBindingDied(ComponentName name) {
376 Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting");
Matthew Ngffb17372018-07-18 12:31:29 -0700377 mCurrentBoundedUserId = -1;
Matthew Ngead8e5a2018-08-20 17:20:05 -0700378 retryConnectionWithBackoff();
Sunny Goyalaac6c882019-02-11 11:57:58 -0800379 disposeInputDispatcher();
Matthew Ng13dbf872017-10-27 11:02:14 -0700380 }
381
382 @Override
383 public void onServiceDisconnected(ComponentName name) {
384 // Do nothing
Matthew Ngffb17372018-07-18 12:31:29 -0700385 mCurrentBoundedUserId = -1;
Sunny Goyalaac6c882019-02-11 11:57:58 -0800386 disposeInputDispatcher();
Matthew Ng13dbf872017-10-27 11:02:14 -0700387 }
388 };
389
Sunny Goyalaac6c882019-02-11 11:57:58 -0800390 private void disposeInputDispatcher() {
391 if (mInputEventDispatcher != null) {
392 mInputEventDispatcher.dispose();
393 mInputEventDispatcher = null;
394 }
395 }
396
397 private InputChannel createNewInputDispatcher() {
398 disposeInputDispatcher();
399
400 InputChannel[] channels = InputChannel.openInputChannelPair("overview-proxy-service");
401 mInputEventDispatcher = new InputEventDispatcher(channels[0], Looper.getMainLooper());
402 return channels[1];
403 }
404
Matthew Ng13dbf872017-10-27 11:02:14 -0700405 private final DeviceProvisionedListener mDeviceProvisionedCallback =
406 new DeviceProvisionedListener() {
407 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800408 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700409 if (mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ngfac87832017-11-10 11:27:29 -0800410 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700411 }
412 }
413
414 @Override
415 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700416 mConnectionBackoffAttempts = 0;
Matthew Ngfac87832017-11-10 11:27:29 -0800417 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700418 }
419 };
420
421 // This is the death handler for the binder from the launcher service
Matthew Ng30c0a022017-11-10 14:06:29 -0800422 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700423 = this::cleanupAfterDeath;
Matthew Ng13dbf872017-10-27 11:02:14 -0700424
Jason Monk196d6392018-12-20 13:25:34 -0500425 @Inject
Jason Monk96a37f42018-12-21 14:45:26 -0500426 public OverviewProxyService(Context context, DeviceProvisionedController provisionController) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700427 mContext = context;
428 mHandler = new Handler();
Jason Monk96a37f42018-12-21 14:45:26 -0500429 mDeviceProvisionedController = provisionController;
Matthew Ng13dbf872017-10-27 11:02:14 -0700430 mConnectionBackoffAttempts = 0;
Sunny Goyal09c12d72018-03-27 10:14:49 -0700431 mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
432 com.android.internal.R.string.config_recentsComponentName));
Winson Chungd95a2252018-04-04 17:02:29 +0000433 mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
434 .setPackage(mRecentsComponentName.getPackageName());
Matthew Ng0769e442018-08-06 15:05:33 -0700435 mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS,
436 getDefaultInteractionFlags());
Lucas Dupin086c6fc2018-10-16 18:06:43 -0700437 mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources());
Lucas Dupinf36d0dc2019-01-09 09:07:50 -0800438 mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
439 .supportsRoundedCornersOnWindows(mContext.getResources());
Matthew Ng30c0a022017-11-10 14:06:29 -0800440
441 // Listen for the package update changes.
Winson Chung67f5c8b2018-09-24 12:09:19 -0700442 if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
Winson Chungd95a2252018-04-04 17:02:29 +0000443 updateEnabledState();
Matthew Ng1b1d3462018-03-02 11:43:38 -0800444 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
445 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
446 filter.addDataScheme("package");
Sunny Goyal09c12d72018-03-27 10:14:49 -0700447 filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
Matthew Ng1b1d3462018-03-02 11:43:38 -0800448 PatternMatcher.PATTERN_LITERAL);
449 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Winson Chungd95a2252018-04-04 17:02:29 +0000450 mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
Matthew Ng1b1d3462018-03-02 11:43:38 -0800451 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700452 }
453
Sunny Goyalaac6c882019-02-11 11:57:58 -0800454 /**
455 * Sets the navbar region which can receive touch inputs
456 */
457 public void onActiveNavBarRegionChanges(Region activeRegion) {
458 mActiveNavBarRegion = activeRegion;
459 dispatchNavButtonBounds();
460 }
461
462 private void dispatchNavButtonBounds() {
463 if (mOverviewProxy != null && mActiveNavBarRegion != null) {
464 try {
465 mOverviewProxy.onActiveNavBarRegionChanges(mActiveNavBarRegion);
466 } catch (RemoteException e) {
467 Log.e(TAG_OPS, "Failed to call onActiveNavBarRegionChanges()", e);
468 }
469 }
470 }
471
Matthew Ngc83b9892018-08-21 16:31:13 -0700472 public float getBackButtonAlpha() {
473 return mBackButtonAlpha;
474 }
475
Hyunyoung Song547e11e2018-10-04 16:32:23 -0700476 public void cleanupAfterDeath() {
477 if (mStatusBarGestureDownEvent != null) {
478 mHandler.post(()-> {
479 StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
480 if (bar != null) {
481 System.out.println("MERONG dispatchNotificationPanelTouchEvent");
482 mStatusBarGestureDownEvent.setAction(MotionEvent.ACTION_CANCEL);
483 bar.dispatchNotificationsPanelTouchEvent(mStatusBarGestureDownEvent);
484 mStatusBarGestureDownEvent.recycle();
485 mStatusBarGestureDownEvent = null;
486 }
487 });
488 }
489 startConnectionToCurrentUser();
490 }
491
Matthew Ng13dbf872017-10-27 11:02:14 -0700492 public void startConnectionToCurrentUser() {
Matthew Ngfac87832017-11-10 11:27:29 -0800493 if (mHandler.getLooper() != Looper.myLooper()) {
494 mHandler.post(mConnectionRunnable);
495 } else {
496 internalConnectToCurrentUser();
497 }
498 }
499
500 private void internalConnectToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800501 disconnectFromLauncherService();
502
Matthew Ng13dbf872017-10-27 11:02:14 -0700503 // If user has not setup yet or already connected, do not try to connect
Winson Chungd95a2252018-04-04 17:02:29 +0000504 if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
Matthew Nge3c5af42018-05-02 16:58:44 -0700505 Log.v(TAG_OPS, "Cannot attempt connection, is setup "
506 + mDeviceProvisionedController.isCurrentUserSetup() + ", is enabled "
507 + isEnabled());
Matthew Ng13dbf872017-10-27 11:02:14 -0700508 return;
509 }
510 mHandler.removeCallbacks(mConnectionRunnable);
Sunny Goyal09c12d72018-03-27 10:14:49 -0700511 Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
512 .setPackage(mRecentsComponentName.getPackageName());
Matthew Ng10b6c41a2018-03-26 18:01:37 -0700513 boolean bound = false;
514 try {
515 bound = mContext.bindServiceAsUser(launcherServiceIntent,
Winson Chunge7cb0c12018-07-30 16:11:38 -0700516 mOverviewServiceConnection,
517 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
Matthew Ng10b6c41a2018-03-26 18:01:37 -0700518 UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
519 } catch (SecurityException e) {
520 Log.e(TAG_OPS, "Unable to bind because of security error", e);
521 }
Matthew Nge3c5af42018-05-02 16:58:44 -0700522 if (bound) {
523 // Ensure that connection has been established even if it thinks it is bound
524 mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
525 } else {
Matthew Ng13dbf872017-10-27 11:02:14 -0700526 // Retry after exponential backoff timeout
Matthew Ngead8e5a2018-08-20 17:20:05 -0700527 retryConnectionWithBackoff();
Matthew Ng13dbf872017-10-27 11:02:14 -0700528 }
529 }
530
Matthew Ngead8e5a2018-08-20 17:20:05 -0700531 private void retryConnectionWithBackoff() {
532 if (mHandler.hasCallbacks(mConnectionRunnable)) {
533 return;
534 }
535 final long timeoutMs = (long) Math.min(
536 Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts), MAX_BACKOFF_MILLIS);
537 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
538 mConnectionBackoffAttempts++;
539 Log.w(TAG_OPS, "Failed to connect on attempt " + mConnectionBackoffAttempts
540 + " will try again in " + timeoutMs + "ms");
541 }
542
Matthew Ng7d05e772017-11-09 14:41:07 -0800543 @Override
544 public void addCallback(OverviewProxyListener listener) {
545 mConnectionCallbacks.add(listener);
546 listener.onConnectionChanged(mOverviewProxy != null);
Winson Chungd95a2252018-04-04 17:02:29 +0000547 listener.onInteractionFlagsChanged(mInteractionFlags);
Matthew Ng7d05e772017-11-09 14:41:07 -0800548 }
549
550 @Override
551 public void removeCallback(OverviewProxyListener listener) {
552 mConnectionCallbacks.remove(listener);
553 }
554
Matthew Ngc1a97b12018-03-28 14:02:00 -0700555 public boolean shouldShowSwipeUpUI() {
Winson Chungd95a2252018-04-04 17:02:29 +0000556 return isEnabled() && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
557 }
558
559 public boolean isEnabled() {
560 return mIsEnabled;
Matthew Ngc1a97b12018-03-28 14:02:00 -0700561 }
562
Matthew Ng13dbf872017-10-27 11:02:14 -0700563 public IOverviewProxy getProxy() {
564 return mOverviewProxy;
565 }
566
Sunny Goyalaac6c882019-02-11 11:57:58 -0800567 public InputEventDispatcher getInputEventDispatcher() {
568 return mInputEventDispatcher;
569 }
570
Matthew Ng8f25fb962018-01-16 17:17:24 -0800571 public int getInteractionFlags() {
572 return mInteractionFlags;
573 }
574
Matthew Ng13dbf872017-10-27 11:02:14 -0700575 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800576 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800577 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800578 mContext.unbindService(mOverviewServiceConnection);
579 mOverviewProxy = null;
Matthew Ng53896452018-05-30 11:27:39 -0700580 notifyBackButtonAlphaChanged(1f, false /* animate */);
Matthew Ng7d05e772017-11-09 14:41:07 -0800581 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800582 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700583 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800584
Matthew Ng0769e442018-08-06 15:05:33 -0700585 private int getDefaultInteractionFlags() {
586 // If there is no settings available use device default or get it from settings
587 final boolean defaultState = getSwipeUpDefaultValue();
588 final boolean swipeUpEnabled = getSwipeUpSettingAvailable()
589 ? getSwipeUpEnabledFromSettings(defaultState)
590 : defaultState;
591 return swipeUpEnabled ? 0 : DEFAULT_DISABLE_SWIPE_UP_STATE;
592 }
593
Matthew Ng53896452018-05-30 11:27:39 -0700594 private void notifyBackButtonAlphaChanged(float alpha, boolean animate) {
595 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
596 mConnectionCallbacks.get(i).onBackButtonAlphaChanged(alpha, animate);
597 }
598 }
599
Matthew Ng7d05e772017-11-09 14:41:07 -0800600 private void notifyConnectionChanged() {
601 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
602 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
603 }
604 }
605
Matthew Ng2ea93b72018-03-14 19:43:18 +0000606 public void notifyQuickStepStarted() {
Winson Chungcbb15a92018-01-25 17:46:16 +0000607 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000608 mConnectionCallbacks.get(i).onQuickStepStarted();
Winson Chungcbb15a92018-01-25 17:46:16 +0000609 }
610 }
611
Tracy Zhou27599052018-04-16 15:47:29 -0700612 public void notifyQuickScrubStarted() {
613 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
614 mConnectionCallbacks.get(i).onQuickScrubStarted();
615 }
616 }
617
Matthew Ng42025e32019-02-20 15:02:58 -0800618 private void notifyAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
619 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
620 mConnectionCallbacks.get(i).onAssistantProgress(progress);
621 }
622 }
623
624 private void notifyStartAssistant(Bundle bundle) {
625 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
626 mConnectionCallbacks.get(i).startAssistant(bundle);
627 }
628 }
629
Winson Chungd95a2252018-04-04 17:02:29 +0000630 private void updateEnabledState() {
Winson Chung6e4b0b562018-04-04 09:13:37 -0700631 mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
Matthew Nga3fee342019-02-25 15:36:37 -0800632 MATCH_SYSTEM_ONLY,
Winson Chungd95a2252018-04-04 17:02:29 +0000633 ActivityManagerWrapper.getInstance().getCurrentUserId()) != null;
634 }
635
Matthew Ng0769e442018-08-06 15:05:33 -0700636 private boolean getSwipeUpDefaultValue() {
637 return mContext.getResources()
638 .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_default);
639 }
640
641 private boolean getSwipeUpSettingAvailable() {
642 return mContext.getResources()
643 .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_setting_available);
644 }
645
646 private boolean getSwipeUpEnabledFromSettings(boolean defaultValue) {
647 return Settings.Secure.getInt(mContext.getContentResolver(),
648 Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED, defaultValue ? 1 : 0) == 1;
649 }
650
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800651 @Override
652 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Matthew Ngbd824572018-01-17 16:25:56 -0800653 pw.println(TAG_OPS + " state:");
Winson Chung387e38b2018-07-09 14:30:54 -0700654 pw.print(" recentsComponentName="); pw.println(mRecentsComponentName);
655 pw.print(" isConnected="); pw.println(mOverviewProxy != null);
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800656 pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
657 .isCurrentUserSetup());
Winson Chung387e38b2018-07-09 14:30:54 -0700658 pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
659 pw.print(" interactionFlags="); pw.println(mInteractionFlags);
660
661 pw.print(" quickStepIntent="); pw.println(mQuickStepIntent);
662 pw.print(" quickStepIntentResolved="); pw.println(isEnabled());
663
Matthew Ng0769e442018-08-06 15:05:33 -0700664 final boolean swipeUpDefaultValue = getSwipeUpDefaultValue();
665 final boolean swipeUpEnabled = getSwipeUpEnabledFromSettings(swipeUpDefaultValue);
666 pw.print(" swipeUpSetting="); pw.println(swipeUpEnabled);
667 pw.print(" swipeUpSettingDefault="); pw.println(swipeUpDefaultValue);
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800668 }
669
Matthew Ng7d05e772017-11-09 14:41:07 -0800670 public interface OverviewProxyListener {
Winson Chungcbb15a92018-01-25 17:46:16 +0000671 default void onConnectionChanged(boolean isConnected) {}
Matthew Ng2ea93b72018-03-14 19:43:18 +0000672 default void onQuickStepStarted() {}
Matthew Ng8f25fb962018-01-16 17:17:24 -0800673 default void onInteractionFlagsChanged(@InteractionType int flags) {}
Tracy Zhou27599052018-04-16 15:47:29 -0700674 default void onOverviewShown(boolean fromHome) {}
675 default void onQuickScrubStarted() {}
Matthew Ng96985e72018-05-08 15:46:13 -0700676 default void onBackButtonAlphaChanged(float alpha, boolean animate) {}
Matthew Ng42025e32019-02-20 15:02:58 -0800677 default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
678 default void startAssistant(Bundle bundle) {}
Matthew Ng7d05e772017-11-09 14:41:07 -0800679 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700680}