blob: b1020cfb5a846038ca75cd2f7dbefc043690e23f [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
17package com.android.systemui;
18
Matthew Ng30c0a022017-11-10 14:06:29 -080019import android.content.BroadcastReceiver;
Matthew Ng13dbf872017-10-27 11:02:14 -070020import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
Matthew Ng30c0a022017-11-10 14:06:29 -080023import android.content.IntentFilter;
Matthew Ng13dbf872017-10-27 11:02:14 -070024import android.content.ServiceConnection;
Winson Chungd95a2252018-04-04 17:02:29 +000025import android.content.pm.PackageManager;
Winson Chung38d31c22017-11-08 14:32:32 -080026import android.graphics.Rect;
27import android.os.Binder;
Matthew Ng13dbf872017-10-27 11:02:14 -070028import android.os.Handler;
29import android.os.IBinder;
Matthew Ngfac87832017-11-10 11:27:29 -080030import android.os.Looper;
Matthew Ng30c0a022017-11-10 14:06:29 -080031import android.os.PatternMatcher;
Matthew Ng13dbf872017-10-27 11:02:14 -070032import android.os.RemoteException;
33import android.os.UserHandle;
34import android.util.Log;
Winson Chung38d31c22017-11-08 14:32:32 -080035import android.view.SurfaceControl;
36
Winson Chung11f53e92017-11-13 17:45:12 -080037import com.android.systemui.OverviewProxyService.OverviewProxyListener;
Winson Chungc1674272018-02-21 10:15:17 -080038import com.android.systemui.recents.events.EventBus;
39import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
Matthew Ng1b1d3462018-03-02 11:43:38 -080040import com.android.systemui.recents.misc.SystemServicesProxy;
Winson Chung38d31c22017-11-08 14:32:32 -080041import com.android.systemui.shared.recents.IOverviewProxy;
42import com.android.systemui.shared.recents.ISystemUiProxy;
Winson Chungd95a2252018-04-04 17:02:29 +000043import com.android.systemui.shared.system.ActivityManagerWrapper;
Winson Chung11f53e92017-11-13 17:45:12 -080044import com.android.systemui.shared.system.GraphicBufferCompat;
Winson Chungcaf2b812018-01-26 10:29:46 -080045import com.android.systemui.statusbar.phone.StatusBar;
Matthew Ng7d05e772017-11-09 14:41:07 -080046import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070047import com.android.systemui.statusbar.policy.DeviceProvisionedController;
48import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Winson Chung11f53e92017-11-13 17:45:12 -080049
Matthew Ng1e43ebd2017-11-14 14:47:05 -080050import java.io.FileDescriptor;
51import java.io.PrintWriter;
Matthew Ng7d05e772017-11-09 14:41:07 -080052import java.util.ArrayList;
53import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070054
Winson Chung6e4b0b562018-04-04 09:13:37 -070055import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
Matthew Ngc1a97b12018-03-28 14:02:00 -070056import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
Matthew Ng8f25fb962018-01-16 17:17:24 -080057import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
58
Matthew Ng13dbf872017-10-27 11:02:14 -070059/**
60 * Class to send information from overview to launcher with a binder.
61 */
Matthew Ng1e43ebd2017-11-14 14:47:05 -080062public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
Matthew Ng13dbf872017-10-27 11:02:14 -070063
Sunny Goyal09c12d72018-03-27 10:14:49 -070064 private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
65
Matthew Ngbd824572018-01-17 16:25:56 -080066 public static final String TAG_OPS = "OverviewProxyService";
67 public static final boolean DEBUG_OVERVIEW_PROXY = false;
Matthew Ng13dbf872017-10-27 11:02:14 -070068 private static final long BACKOFF_MILLIS = 5000;
69
70 private final Context mContext;
71 private final Handler mHandler;
Matthew Ngfac87832017-11-10 11:27:29 -080072 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
Sunny Goyal09c12d72018-03-27 10:14:49 -070073 private final ComponentName mRecentsComponentName;
Matthew Ng13dbf872017-10-27 11:02:14 -070074 private final DeviceProvisionedController mDeviceProvisionedController
75 = Dependency.get(DeviceProvisionedController.class);
Matthew Ng7d05e772017-11-09 14:41:07 -080076 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Winson Chungd95a2252018-04-04 17:02:29 +000077 private final Intent mQuickStepIntent;
Matthew Ng13dbf872017-10-27 11:02:14 -070078
79 private IOverviewProxy mOverviewProxy;
80 private int mConnectionBackoffAttempts;
Tony Wickham05c1f852018-02-06 12:32:54 -080081 private CharSequence mOnboardingText;
Matthew Ng8f25fb962018-01-16 17:17:24 -080082 private @InteractionType int mInteractionFlags;
Winson Chungd95a2252018-04-04 17:02:29 +000083 private boolean mIsEnabled;
Matthew Ng13dbf872017-10-27 11:02:14 -070084
Winson Chung38d31c22017-11-08 14:32:32 -080085 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
Winson Chungcaf2b812018-01-26 10:29:46 -080086
Winson Chung11f53e92017-11-13 17:45:12 -080087 public GraphicBufferCompat screenshot(Rect sourceCrop, int width, int height, int minLayer,
88 int maxLayer, boolean useIdentityTransform, int rotation) {
Winson Chung38d31c22017-11-08 14:32:32 -080089 long token = Binder.clearCallingIdentity();
90 try {
Winson Chung11f53e92017-11-13 17:45:12 -080091 return new GraphicBufferCompat(SurfaceControl.screenshotToBuffer(sourceCrop, width,
92 height, minLayer, maxLayer, useIdentityTransform, rotation));
Winson Chung38d31c22017-11-08 14:32:32 -080093 } finally {
94 Binder.restoreCallingIdentity(token);
95 }
96 }
Winson Chungcbb15a92018-01-25 17:46:16 +000097
Winson Chungcaf2b812018-01-26 10:29:46 -080098 public void startScreenPinning(int taskId) {
99 long token = Binder.clearCallingIdentity();
100 try {
101 mHandler.post(() -> {
102 StatusBar statusBar = ((SystemUIApplication) mContext).getComponent(
103 StatusBar.class);
104 if (statusBar != null) {
105 statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
106 }
107 });
108 } finally {
109 Binder.restoreCallingIdentity(token);
110 }
111 }
112
Winson Chungc1674272018-02-21 10:15:17 -0800113 public void onSplitScreenInvoked() {
114 long token = Binder.clearCallingIdentity();
115 try {
116 EventBus.getDefault().post(new DockedFirstAnimationFrameEvent());
117 } finally {
118 Binder.restoreCallingIdentity(token);
119 }
120 }
121
Tony Wickham05c1f852018-02-06 12:32:54 -0800122 public void setRecentsOnboardingText(CharSequence text) {
123 mOnboardingText = text;
124 }
Matthew Ng8f25fb962018-01-16 17:17:24 -0800125
126 public void setInteractionState(@InteractionType int flags) {
127 long token = Binder.clearCallingIdentity();
128 try {
129 if (mInteractionFlags != flags) {
130 mInteractionFlags = flags;
131 mHandler.post(() -> {
132 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
133 mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
134 }
135 });
136 }
137 } finally {
Winson Chungd95a2252018-04-04 17:02:29 +0000138 Prefs.putInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, mInteractionFlags);
Matthew Ng8f25fb962018-01-16 17:17:24 -0800139 Binder.restoreCallingIdentity(token);
140 }
141 }
Winson Chung38d31c22017-11-08 14:32:32 -0800142 };
143
Winson Chungd95a2252018-04-04 17:02:29 +0000144 private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
Matthew Ng30c0a022017-11-10 14:06:29 -0800145 @Override
146 public void onReceive(Context context, Intent intent) {
Winson Chungd95a2252018-04-04 17:02:29 +0000147 updateEnabledState();
148
149 // When launcher service is disabled, reset interaction flags because it is inactive
150 if (!isEnabled()) {
151 mInteractionFlags = 0;
152 Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS);
153 }
154
Matthew Ng30c0a022017-11-10 14:06:29 -0800155 // Reconnect immediately, instead of waiting for resume to arrive.
156 startConnectionToCurrentUser();
157 }
158 };
159
Matthew Ng13dbf872017-10-27 11:02:14 -0700160 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
161 @Override
162 public void onServiceConnected(ComponentName name, IBinder service) {
163 if (service != null) {
164 mConnectionBackoffAttempts = 0;
165 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
166 // Listen for launcher's death
167 try {
168 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
169 } catch (RemoteException e) {
Matthew Ngbd824572018-01-17 16:25:56 -0800170 Log.e(TAG_OPS, "Lost connection to launcher service", e);
Matthew Ng13dbf872017-10-27 11:02:14 -0700171 }
Winson Chung38d31c22017-11-08 14:32:32 -0800172 try {
173 mOverviewProxy.onBind(mSysUiProxy);
174 } catch (RemoteException e) {
Matthew Ngbd824572018-01-17 16:25:56 -0800175 Log.e(TAG_OPS, "Failed to call onBind()", e);
Winson Chung38d31c22017-11-08 14:32:32 -0800176 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800177 notifyConnectionChanged();
Matthew Ng13dbf872017-10-27 11:02:14 -0700178 }
179 }
180
181 @Override
182 public void onServiceDisconnected(ComponentName name) {
183 // Do nothing
184 }
185 };
186
187 private final DeviceProvisionedListener mDeviceProvisionedCallback =
188 new DeviceProvisionedListener() {
189 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800190 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700191 if (mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ngfac87832017-11-10 11:27:29 -0800192 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700193 }
194 }
195
196 @Override
197 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700198 mConnectionBackoffAttempts = 0;
Matthew Ngfac87832017-11-10 11:27:29 -0800199 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700200 }
201 };
202
203 // This is the death handler for the binder from the launcher service
Matthew Ng30c0a022017-11-10 14:06:29 -0800204 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
205 = this::startConnectionToCurrentUser;
Matthew Ng13dbf872017-10-27 11:02:14 -0700206
207 public OverviewProxyService(Context context) {
208 mContext = context;
209 mHandler = new Handler();
210 mConnectionBackoffAttempts = 0;
Sunny Goyal09c12d72018-03-27 10:14:49 -0700211 mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
212 com.android.internal.R.string.config_recentsComponentName));
Winson Chungd95a2252018-04-04 17:02:29 +0000213 mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
214 .setPackage(mRecentsComponentName.getPackageName());
215 mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, 0);
Matthew Ng30c0a022017-11-10 14:06:29 -0800216
217 // Listen for the package update changes.
Matthew Ng1b1d3462018-03-02 11:43:38 -0800218 if (SystemServicesProxy.getInstance(context)
219 .isSystemUser(mDeviceProvisionedController.getCurrentUser())) {
Winson Chungd95a2252018-04-04 17:02:29 +0000220 updateEnabledState();
Matthew Ng1b1d3462018-03-02 11:43:38 -0800221 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
222 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
223 filter.addDataScheme("package");
Sunny Goyal09c12d72018-03-27 10:14:49 -0700224 filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
Matthew Ng1b1d3462018-03-02 11:43:38 -0800225 PatternMatcher.PATTERN_LITERAL);
226 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Winson Chungd95a2252018-04-04 17:02:29 +0000227 mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
Matthew Ng1b1d3462018-03-02 11:43:38 -0800228 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700229 }
230
231 public void startConnectionToCurrentUser() {
Matthew Ngfac87832017-11-10 11:27:29 -0800232 if (mHandler.getLooper() != Looper.myLooper()) {
233 mHandler.post(mConnectionRunnable);
234 } else {
235 internalConnectToCurrentUser();
236 }
237 }
238
239 private void internalConnectToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800240 disconnectFromLauncherService();
241
Matthew Ng13dbf872017-10-27 11:02:14 -0700242 // If user has not setup yet or already connected, do not try to connect
Winson Chungd95a2252018-04-04 17:02:29 +0000243 if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700244 return;
245 }
246 mHandler.removeCallbacks(mConnectionRunnable);
Sunny Goyal09c12d72018-03-27 10:14:49 -0700247 Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
248 .setPackage(mRecentsComponentName.getPackageName());
Matthew Ng10b6c41a2018-03-26 18:01:37 -0700249 boolean bound = false;
250 try {
251 bound = mContext.bindServiceAsUser(launcherServiceIntent,
252 mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
253 UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
254 } catch (SecurityException e) {
255 Log.e(TAG_OPS, "Unable to bind because of security error", e);
256 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700257 if (!bound) {
258 // Retry after exponential backoff timeout
259 final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
260 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
261 mConnectionBackoffAttempts++;
262 }
263 }
264
Matthew Ng7d05e772017-11-09 14:41:07 -0800265 @Override
266 public void addCallback(OverviewProxyListener listener) {
267 mConnectionCallbacks.add(listener);
268 listener.onConnectionChanged(mOverviewProxy != null);
Winson Chungd95a2252018-04-04 17:02:29 +0000269 listener.onInteractionFlagsChanged(mInteractionFlags);
Matthew Ng7d05e772017-11-09 14:41:07 -0800270 }
271
272 @Override
273 public void removeCallback(OverviewProxyListener listener) {
274 mConnectionCallbacks.remove(listener);
275 }
276
Matthew Ngc1a97b12018-03-28 14:02:00 -0700277 public boolean shouldShowSwipeUpUI() {
Winson Chungd95a2252018-04-04 17:02:29 +0000278 return isEnabled() && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
279 }
280
281 public boolean isEnabled() {
282 return mIsEnabled;
Matthew Ngc1a97b12018-03-28 14:02:00 -0700283 }
284
Matthew Ng13dbf872017-10-27 11:02:14 -0700285 public IOverviewProxy getProxy() {
286 return mOverviewProxy;
287 }
288
Tony Wickham05c1f852018-02-06 12:32:54 -0800289 public CharSequence getOnboardingText() {
290 return mOnboardingText;
Tony Wickhamfb63fe82018-01-16 12:14:06 -0800291 }
292
Matthew Ng8f25fb962018-01-16 17:17:24 -0800293 public int getInteractionFlags() {
294 return mInteractionFlags;
295 }
296
Matthew Ng13dbf872017-10-27 11:02:14 -0700297 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800298 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800299 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800300 mContext.unbindService(mOverviewServiceConnection);
301 mOverviewProxy = null;
Matthew Ng7d05e772017-11-09 14:41:07 -0800302 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800303 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700304 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800305
306 private void notifyConnectionChanged() {
307 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
308 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
309 }
310 }
311
Matthew Ng2ea93b72018-03-14 19:43:18 +0000312 public void notifyQuickStepStarted() {
Winson Chungcbb15a92018-01-25 17:46:16 +0000313 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
Matthew Ng2ea93b72018-03-14 19:43:18 +0000314 mConnectionCallbacks.get(i).onQuickStepStarted();
Winson Chungcbb15a92018-01-25 17:46:16 +0000315 }
316 }
317
Winson Chungd95a2252018-04-04 17:02:29 +0000318 private void updateEnabledState() {
Winson Chung6e4b0b562018-04-04 09:13:37 -0700319 mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
320 MATCH_DIRECT_BOOT_UNAWARE,
Winson Chungd95a2252018-04-04 17:02:29 +0000321 ActivityManagerWrapper.getInstance().getCurrentUserId()) != null;
322 }
323
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800324 @Override
325 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Matthew Ngbd824572018-01-17 16:25:56 -0800326 pw.println(TAG_OPS + " state:");
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800327 pw.print(" mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
328 pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
329 .isCurrentUserSetup());
330 pw.print(" isConnected="); pw.println(mOverviewProxy != null);
331 }
332
Matthew Ng7d05e772017-11-09 14:41:07 -0800333 public interface OverviewProxyListener {
Winson Chungcbb15a92018-01-25 17:46:16 +0000334 default void onConnectionChanged(boolean isConnected) {}
Matthew Ng2ea93b72018-03-14 19:43:18 +0000335 default void onQuickStepStarted() {}
Matthew Ng8f25fb962018-01-16 17:17:24 -0800336 default void onInteractionFlagsChanged(@InteractionType int flags) {}
Matthew Ng7d05e772017-11-09 14:41:07 -0800337 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700338}