blob: 041af0e4711938fb11616b3c80a02c2991995add [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 Chung38d31c22017-11-08 14:32:32 -080025import android.graphics.Rect;
26import android.os.Binder;
Matthew Ng13dbf872017-10-27 11:02:14 -070027import android.os.Handler;
28import android.os.IBinder;
Matthew Ngfac87832017-11-10 11:27:29 -080029import android.os.Looper;
Matthew Ng30c0a022017-11-10 14:06:29 -080030import android.os.PatternMatcher;
Matthew Ng13dbf872017-10-27 11:02:14 -070031import android.os.RemoteException;
32import android.os.UserHandle;
33import android.util.Log;
Winson Chung38d31c22017-11-08 14:32:32 -080034import android.view.SurfaceControl;
35
Winson Chung11f53e92017-11-13 17:45:12 -080036import com.android.systemui.OverviewProxyService.OverviewProxyListener;
Winson Chungc1674272018-02-21 10:15:17 -080037import com.android.systemui.recents.events.EventBus;
38import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
Matthew Ng1b1d3462018-03-02 11:43:38 -080039import com.android.systemui.recents.misc.SystemServicesProxy;
Winson Chung38d31c22017-11-08 14:32:32 -080040import com.android.systemui.shared.recents.IOverviewProxy;
41import com.android.systemui.shared.recents.ISystemUiProxy;
Winson Chung11f53e92017-11-13 17:45:12 -080042import com.android.systemui.shared.system.GraphicBufferCompat;
Winson Chungcaf2b812018-01-26 10:29:46 -080043import com.android.systemui.statusbar.phone.StatusBar;
Matthew Ng7d05e772017-11-09 14:41:07 -080044import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070045import com.android.systemui.statusbar.policy.DeviceProvisionedController;
46import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Winson Chung11f53e92017-11-13 17:45:12 -080047
Matthew Ng1e43ebd2017-11-14 14:47:05 -080048import java.io.FileDescriptor;
49import java.io.PrintWriter;
Matthew Ng7d05e772017-11-09 14:41:07 -080050import java.util.ArrayList;
51import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070052
Matthew Ng8f25fb962018-01-16 17:17:24 -080053import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
54
Matthew Ng13dbf872017-10-27 11:02:14 -070055/**
56 * Class to send information from overview to launcher with a binder.
57 */
Matthew Ng1e43ebd2017-11-14 14:47:05 -080058public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
Matthew Ng13dbf872017-10-27 11:02:14 -070059
Matthew Ngbd824572018-01-17 16:25:56 -080060 public static final String TAG_OPS = "OverviewProxyService";
61 public static final boolean DEBUG_OVERVIEW_PROXY = false;
Matthew Ng13dbf872017-10-27 11:02:14 -070062 private static final long BACKOFF_MILLIS = 5000;
63
64 private final Context mContext;
65 private final Handler mHandler;
Matthew Ngfac87832017-11-10 11:27:29 -080066 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
Matthew Ng30c0a022017-11-10 14:06:29 -080067 private final ComponentName mLauncherComponentName;
Matthew Ng13dbf872017-10-27 11:02:14 -070068 private final DeviceProvisionedController mDeviceProvisionedController
69 = Dependency.get(DeviceProvisionedController.class);
Matthew Ng7d05e772017-11-09 14:41:07 -080070 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Matthew Ng13dbf872017-10-27 11:02:14 -070071
72 private IOverviewProxy mOverviewProxy;
73 private int mConnectionBackoffAttempts;
Tony Wickham05c1f852018-02-06 12:32:54 -080074 private CharSequence mOnboardingText;
Matthew Ng8f25fb962018-01-16 17:17:24 -080075 private @InteractionType int mInteractionFlags;
Matthew Ng13dbf872017-10-27 11:02:14 -070076
Winson Chung38d31c22017-11-08 14:32:32 -080077 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
Winson Chungcaf2b812018-01-26 10:29:46 -080078
Winson Chung11f53e92017-11-13 17:45:12 -080079 public GraphicBufferCompat screenshot(Rect sourceCrop, int width, int height, int minLayer,
80 int maxLayer, boolean useIdentityTransform, int rotation) {
Winson Chung38d31c22017-11-08 14:32:32 -080081 long token = Binder.clearCallingIdentity();
82 try {
Winson Chung11f53e92017-11-13 17:45:12 -080083 return new GraphicBufferCompat(SurfaceControl.screenshotToBuffer(sourceCrop, width,
84 height, minLayer, maxLayer, useIdentityTransform, rotation));
Winson Chung38d31c22017-11-08 14:32:32 -080085 } finally {
86 Binder.restoreCallingIdentity(token);
87 }
88 }
Winson Chungcbb15a92018-01-25 17:46:16 +000089
Winson Chungcaf2b812018-01-26 10:29:46 -080090 public void startScreenPinning(int taskId) {
91 long token = Binder.clearCallingIdentity();
92 try {
93 mHandler.post(() -> {
94 StatusBar statusBar = ((SystemUIApplication) mContext).getComponent(
95 StatusBar.class);
96 if (statusBar != null) {
97 statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
98 }
99 });
100 } finally {
101 Binder.restoreCallingIdentity(token);
102 }
103 }
104
Winson Chungcbb15a92018-01-25 17:46:16 +0000105 public void onRecentsAnimationStarted() {
106 long token = Binder.clearCallingIdentity();
107 try {
Winson Chung58bd4392018-02-08 17:53:26 -0800108 mHandler.post(OverviewProxyService.this::notifyRecentsAnimationStarted);
Winson Chungcbb15a92018-01-25 17:46:16 +0000109 } finally {
110 Binder.restoreCallingIdentity(token);
111 }
112 }
Tony Wickham05c1f852018-02-06 12:32:54 -0800113
Winson Chungc1674272018-02-21 10:15:17 -0800114 public void onSplitScreenInvoked() {
115 long token = Binder.clearCallingIdentity();
116 try {
117 EventBus.getDefault().post(new DockedFirstAnimationFrameEvent());
118 } finally {
119 Binder.restoreCallingIdentity(token);
120 }
121 }
122
Tony Wickham05c1f852018-02-06 12:32:54 -0800123 public void setRecentsOnboardingText(CharSequence text) {
124 mOnboardingText = text;
125 }
Matthew Ng8f25fb962018-01-16 17:17:24 -0800126
127 public void setInteractionState(@InteractionType int flags) {
128 long token = Binder.clearCallingIdentity();
129 try {
130 if (mInteractionFlags != flags) {
131 mInteractionFlags = flags;
132 mHandler.post(() -> {
133 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
134 mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
135 }
136 });
137 }
138 } finally {
139 Binder.restoreCallingIdentity(token);
140 }
141 }
Winson Chung38d31c22017-11-08 14:32:32 -0800142 };
143
Matthew Ng30c0a022017-11-10 14:06:29 -0800144 private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
145 @Override
146 public void onReceive(Context context, Intent intent) {
147 // Reconnect immediately, instead of waiting for resume to arrive.
148 startConnectionToCurrentUser();
149 }
150 };
151
Matthew Ng13dbf872017-10-27 11:02:14 -0700152 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
153 @Override
154 public void onServiceConnected(ComponentName name, IBinder service) {
155 if (service != null) {
156 mConnectionBackoffAttempts = 0;
157 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
158 // Listen for launcher's death
159 try {
160 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
161 } catch (RemoteException e) {
Matthew Ngbd824572018-01-17 16:25:56 -0800162 Log.e(TAG_OPS, "Lost connection to launcher service", e);
Matthew Ng13dbf872017-10-27 11:02:14 -0700163 }
Winson Chung38d31c22017-11-08 14:32:32 -0800164 try {
165 mOverviewProxy.onBind(mSysUiProxy);
166 } catch (RemoteException e) {
Matthew Ngbd824572018-01-17 16:25:56 -0800167 Log.e(TAG_OPS, "Failed to call onBind()", e);
Winson Chung38d31c22017-11-08 14:32:32 -0800168 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800169 notifyConnectionChanged();
Matthew Ng13dbf872017-10-27 11:02:14 -0700170 }
171 }
172
173 @Override
174 public void onServiceDisconnected(ComponentName name) {
175 // Do nothing
176 }
177 };
178
179 private final DeviceProvisionedListener mDeviceProvisionedCallback =
180 new DeviceProvisionedListener() {
181 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800182 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700183 if (mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ngfac87832017-11-10 11:27:29 -0800184 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700185 }
186 }
187
188 @Override
189 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700190 mConnectionBackoffAttempts = 0;
Matthew Ngfac87832017-11-10 11:27:29 -0800191 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700192 }
193 };
194
195 // This is the death handler for the binder from the launcher service
Matthew Ng30c0a022017-11-10 14:06:29 -0800196 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
197 = this::startConnectionToCurrentUser;
Matthew Ng13dbf872017-10-27 11:02:14 -0700198
199 public OverviewProxyService(Context context) {
200 mContext = context;
201 mHandler = new Handler();
202 mConnectionBackoffAttempts = 0;
Matthew Ng30c0a022017-11-10 14:06:29 -0800203 mLauncherComponentName = ComponentName
204 .unflattenFromString(context.getString(R.string.config_overviewServiceComponent));
Matthew Ng30c0a022017-11-10 14:06:29 -0800205
206 // Listen for the package update changes.
Matthew Ng1b1d3462018-03-02 11:43:38 -0800207 if (SystemServicesProxy.getInstance(context)
208 .isSystemUser(mDeviceProvisionedController.getCurrentUser())) {
209 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
210 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
211 filter.addDataScheme("package");
212 filter.addDataSchemeSpecificPart(mLauncherComponentName.getPackageName(),
213 PatternMatcher.PATTERN_LITERAL);
214 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
215 mContext.registerReceiver(mLauncherAddedReceiver, filter);
216 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700217 }
218
219 public void startConnectionToCurrentUser() {
Matthew Ngfac87832017-11-10 11:27:29 -0800220 if (mHandler.getLooper() != Looper.myLooper()) {
221 mHandler.post(mConnectionRunnable);
222 } else {
223 internalConnectToCurrentUser();
224 }
225 }
226
227 private void internalConnectToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800228 disconnectFromLauncherService();
229
Matthew Ng13dbf872017-10-27 11:02:14 -0700230 // If user has not setup yet or already connected, do not try to connect
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800231 if (!mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700232 return;
233 }
234 mHandler.removeCallbacks(mConnectionRunnable);
235 Intent launcherServiceIntent = new Intent();
Matthew Ng30c0a022017-11-10 14:06:29 -0800236 launcherServiceIntent.setComponent(mLauncherComponentName);
Matthew Ng13dbf872017-10-27 11:02:14 -0700237 boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
238 mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
Matthew Ng09e6fbd2018-02-01 16:54:16 -0800239 UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
Matthew Ng13dbf872017-10-27 11:02:14 -0700240 if (!bound) {
241 // Retry after exponential backoff timeout
242 final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
243 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
244 mConnectionBackoffAttempts++;
245 }
246 }
247
Matthew Ng7d05e772017-11-09 14:41:07 -0800248 @Override
249 public void addCallback(OverviewProxyListener listener) {
250 mConnectionCallbacks.add(listener);
251 listener.onConnectionChanged(mOverviewProxy != null);
252 }
253
254 @Override
255 public void removeCallback(OverviewProxyListener listener) {
256 mConnectionCallbacks.remove(listener);
257 }
258
Matthew Ng13dbf872017-10-27 11:02:14 -0700259 public IOverviewProxy getProxy() {
260 return mOverviewProxy;
261 }
262
Tony Wickham05c1f852018-02-06 12:32:54 -0800263 public CharSequence getOnboardingText() {
264 return mOnboardingText;
Tony Wickhamfb63fe82018-01-16 12:14:06 -0800265 }
266
Matthew Ng8f25fb962018-01-16 17:17:24 -0800267 public int getInteractionFlags() {
268 return mInteractionFlags;
269 }
270
Matthew Ng13dbf872017-10-27 11:02:14 -0700271 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800272 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800273 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800274 mContext.unbindService(mOverviewServiceConnection);
275 mOverviewProxy = null;
Matthew Ng7d05e772017-11-09 14:41:07 -0800276 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800277 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700278 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800279
280 private void notifyConnectionChanged() {
281 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
282 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
283 }
284 }
285
Winson Chungcbb15a92018-01-25 17:46:16 +0000286 private void notifyRecentsAnimationStarted() {
287 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
288 mConnectionCallbacks.get(i).onRecentsAnimationStarted();
289 }
290 }
291
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800292 @Override
293 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Matthew Ngbd824572018-01-17 16:25:56 -0800294 pw.println(TAG_OPS + " state:");
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800295 pw.print(" mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
296 pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
297 .isCurrentUserSetup());
298 pw.print(" isConnected="); pw.println(mOverviewProxy != null);
299 }
300
Matthew Ng7d05e772017-11-09 14:41:07 -0800301 public interface OverviewProxyListener {
Winson Chungcbb15a92018-01-25 17:46:16 +0000302 default void onConnectionChanged(boolean isConnected) {}
303 default void onRecentsAnimationStarted() {}
Matthew Ng8f25fb962018-01-16 17:17:24 -0800304 default void onInteractionFlagsChanged(@InteractionType int flags) {}
Matthew Ng7d05e772017-11-09 14:41:07 -0800305 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700306}