blob: 1185f45469df6ee5099e72fbd533fcf08ad02b76 [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 Chung38d31c22017-11-08 14:32:32 -080037import com.android.systemui.shared.recents.IOverviewProxy;
38import com.android.systemui.shared.recents.ISystemUiProxy;
Winson Chung11f53e92017-11-13 17:45:12 -080039import com.android.systemui.shared.system.GraphicBufferCompat;
Winson Chungcaf2b812018-01-26 10:29:46 -080040import com.android.systemui.statusbar.phone.StatusBar;
Matthew Ng7d05e772017-11-09 14:41:07 -080041import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070042import com.android.systemui.statusbar.policy.DeviceProvisionedController;
43import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Winson Chung11f53e92017-11-13 17:45:12 -080044
Matthew Ng1e43ebd2017-11-14 14:47:05 -080045import java.io.FileDescriptor;
46import java.io.PrintWriter;
Matthew Ng7d05e772017-11-09 14:41:07 -080047import java.util.ArrayList;
48import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070049
Matthew Ng8f25fb962018-01-16 17:17:24 -080050import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
51
Matthew Ng13dbf872017-10-27 11:02:14 -070052/**
53 * Class to send information from overview to launcher with a binder.
54 */
Matthew Ng1e43ebd2017-11-14 14:47:05 -080055public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
Matthew Ng13dbf872017-10-27 11:02:14 -070056
Matthew Ngbd824572018-01-17 16:25:56 -080057 public static final String TAG_OPS = "OverviewProxyService";
58 public static final boolean DEBUG_OVERVIEW_PROXY = false;
Matthew Ng13dbf872017-10-27 11:02:14 -070059 private static final long BACKOFF_MILLIS = 5000;
60
61 private final Context mContext;
62 private final Handler mHandler;
Matthew Ngfac87832017-11-10 11:27:29 -080063 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
Matthew Ng30c0a022017-11-10 14:06:29 -080064 private final ComponentName mLauncherComponentName;
Matthew Ng13dbf872017-10-27 11:02:14 -070065 private final DeviceProvisionedController mDeviceProvisionedController
66 = Dependency.get(DeviceProvisionedController.class);
Matthew Ng7d05e772017-11-09 14:41:07 -080067 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Matthew Ng13dbf872017-10-27 11:02:14 -070068
69 private IOverviewProxy mOverviewProxy;
70 private int mConnectionBackoffAttempts;
Tony Wickham05c1f852018-02-06 12:32:54 -080071 private CharSequence mOnboardingText;
Matthew Ng8f25fb962018-01-16 17:17:24 -080072 private @InteractionType int mInteractionFlags;
Matthew Ng13dbf872017-10-27 11:02:14 -070073
Winson Chung38d31c22017-11-08 14:32:32 -080074 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
Winson Chungcaf2b812018-01-26 10:29:46 -080075
Winson Chung11f53e92017-11-13 17:45:12 -080076 public GraphicBufferCompat screenshot(Rect sourceCrop, int width, int height, int minLayer,
77 int maxLayer, boolean useIdentityTransform, int rotation) {
Winson Chung38d31c22017-11-08 14:32:32 -080078 long token = Binder.clearCallingIdentity();
79 try {
Winson Chung11f53e92017-11-13 17:45:12 -080080 return new GraphicBufferCompat(SurfaceControl.screenshotToBuffer(sourceCrop, width,
81 height, minLayer, maxLayer, useIdentityTransform, rotation));
Winson Chung38d31c22017-11-08 14:32:32 -080082 } finally {
83 Binder.restoreCallingIdentity(token);
84 }
85 }
Winson Chungcbb15a92018-01-25 17:46:16 +000086
Winson Chungcaf2b812018-01-26 10:29:46 -080087 public void startScreenPinning(int taskId) {
88 long token = Binder.clearCallingIdentity();
89 try {
90 mHandler.post(() -> {
91 StatusBar statusBar = ((SystemUIApplication) mContext).getComponent(
92 StatusBar.class);
93 if (statusBar != null) {
94 statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
95 }
96 });
97 } finally {
98 Binder.restoreCallingIdentity(token);
99 }
100 }
101
Winson Chungcbb15a92018-01-25 17:46:16 +0000102 public void onRecentsAnimationStarted() {
103 long token = Binder.clearCallingIdentity();
104 try {
Winson Chung58bd4392018-02-08 17:53:26 -0800105 mHandler.post(OverviewProxyService.this::notifyRecentsAnimationStarted);
Winson Chungcbb15a92018-01-25 17:46:16 +0000106 } finally {
107 Binder.restoreCallingIdentity(token);
108 }
109 }
Tony Wickham05c1f852018-02-06 12:32:54 -0800110
111 public void setRecentsOnboardingText(CharSequence text) {
112 mOnboardingText = text;
113 }
Matthew Ng8f25fb962018-01-16 17:17:24 -0800114
115 public void setInteractionState(@InteractionType int flags) {
116 long token = Binder.clearCallingIdentity();
117 try {
118 if (mInteractionFlags != flags) {
119 mInteractionFlags = flags;
120 mHandler.post(() -> {
121 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
122 mConnectionCallbacks.get(i).onInteractionFlagsChanged(flags);
123 }
124 });
125 }
126 } finally {
127 Binder.restoreCallingIdentity(token);
128 }
129 }
Winson Chung38d31c22017-11-08 14:32:32 -0800130 };
131
Matthew Ng30c0a022017-11-10 14:06:29 -0800132 private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
133 @Override
134 public void onReceive(Context context, Intent intent) {
135 // Reconnect immediately, instead of waiting for resume to arrive.
136 startConnectionToCurrentUser();
137 }
138 };
139
Matthew Ng13dbf872017-10-27 11:02:14 -0700140 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
141 @Override
142 public void onServiceConnected(ComponentName name, IBinder service) {
143 if (service != null) {
144 mConnectionBackoffAttempts = 0;
145 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
146 // Listen for launcher's death
147 try {
148 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
149 } catch (RemoteException e) {
Matthew Ngbd824572018-01-17 16:25:56 -0800150 Log.e(TAG_OPS, "Lost connection to launcher service", e);
Matthew Ng13dbf872017-10-27 11:02:14 -0700151 }
Winson Chung38d31c22017-11-08 14:32:32 -0800152 try {
153 mOverviewProxy.onBind(mSysUiProxy);
154 } catch (RemoteException e) {
Matthew Ngbd824572018-01-17 16:25:56 -0800155 Log.e(TAG_OPS, "Failed to call onBind()", e);
Winson Chung38d31c22017-11-08 14:32:32 -0800156 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800157 notifyConnectionChanged();
Matthew Ng13dbf872017-10-27 11:02:14 -0700158 }
159 }
160
161 @Override
162 public void onServiceDisconnected(ComponentName name) {
163 // Do nothing
164 }
165 };
166
167 private final DeviceProvisionedListener mDeviceProvisionedCallback =
168 new DeviceProvisionedListener() {
169 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800170 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700171 if (mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ngfac87832017-11-10 11:27:29 -0800172 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700173 }
174 }
175
176 @Override
177 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700178 mConnectionBackoffAttempts = 0;
Matthew Ngfac87832017-11-10 11:27:29 -0800179 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700180 }
181 };
182
183 // This is the death handler for the binder from the launcher service
Matthew Ng30c0a022017-11-10 14:06:29 -0800184 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
185 = this::startConnectionToCurrentUser;
Matthew Ng13dbf872017-10-27 11:02:14 -0700186
187 public OverviewProxyService(Context context) {
188 mContext = context;
189 mHandler = new Handler();
190 mConnectionBackoffAttempts = 0;
Matthew Ng30c0a022017-11-10 14:06:29 -0800191 mLauncherComponentName = ComponentName
192 .unflattenFromString(context.getString(R.string.config_overviewServiceComponent));
Matthew Ng13dbf872017-10-27 11:02:14 -0700193 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
Matthew Ng30c0a022017-11-10 14:06:29 -0800194
195 // Listen for the package update changes.
196 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
197 filter.addDataScheme("package");
198 filter.addDataSchemeSpecificPart(mLauncherComponentName.getPackageName(),
199 PatternMatcher.PATTERN_LITERAL);
Matthew Ngc361fa12018-01-08 12:50:27 -0800200 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Matthew Ng30c0a022017-11-10 14:06:29 -0800201 mContext.registerReceiver(mLauncherAddedReceiver, filter);
Matthew Ng13dbf872017-10-27 11:02:14 -0700202 }
203
204 public void startConnectionToCurrentUser() {
Matthew Ngfac87832017-11-10 11:27:29 -0800205 if (mHandler.getLooper() != Looper.myLooper()) {
206 mHandler.post(mConnectionRunnable);
207 } else {
208 internalConnectToCurrentUser();
209 }
210 }
211
212 private void internalConnectToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800213 disconnectFromLauncherService();
214
Matthew Ng13dbf872017-10-27 11:02:14 -0700215 // If user has not setup yet or already connected, do not try to connect
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800216 if (!mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700217 return;
218 }
219 mHandler.removeCallbacks(mConnectionRunnable);
220 Intent launcherServiceIntent = new Intent();
Matthew Ng30c0a022017-11-10 14:06:29 -0800221 launcherServiceIntent.setComponent(mLauncherComponentName);
Matthew Ng13dbf872017-10-27 11:02:14 -0700222 boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
223 mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
Matthew Ng09e6fbd2018-02-01 16:54:16 -0800224 UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
Matthew Ng13dbf872017-10-27 11:02:14 -0700225 if (!bound) {
226 // Retry after exponential backoff timeout
227 final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
228 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
229 mConnectionBackoffAttempts++;
230 }
231 }
232
Matthew Ng7d05e772017-11-09 14:41:07 -0800233 @Override
234 public void addCallback(OverviewProxyListener listener) {
235 mConnectionCallbacks.add(listener);
236 listener.onConnectionChanged(mOverviewProxy != null);
237 }
238
239 @Override
240 public void removeCallback(OverviewProxyListener listener) {
241 mConnectionCallbacks.remove(listener);
242 }
243
Matthew Ng13dbf872017-10-27 11:02:14 -0700244 public IOverviewProxy getProxy() {
245 return mOverviewProxy;
246 }
247
Tony Wickham05c1f852018-02-06 12:32:54 -0800248 public CharSequence getOnboardingText() {
249 return mOnboardingText;
Tony Wickhamfb63fe82018-01-16 12:14:06 -0800250 }
251
Matthew Ng8f25fb962018-01-16 17:17:24 -0800252 public int getInteractionFlags() {
253 return mInteractionFlags;
254 }
255
Matthew Ng13dbf872017-10-27 11:02:14 -0700256 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800257 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800258 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800259 mContext.unbindService(mOverviewServiceConnection);
260 mOverviewProxy = null;
Matthew Ng7d05e772017-11-09 14:41:07 -0800261 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800262 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700263 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800264
265 private void notifyConnectionChanged() {
266 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
267 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
268 }
269 }
270
Winson Chungcbb15a92018-01-25 17:46:16 +0000271 private void notifyRecentsAnimationStarted() {
272 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
273 mConnectionCallbacks.get(i).onRecentsAnimationStarted();
274 }
275 }
276
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800277 @Override
278 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Matthew Ngbd824572018-01-17 16:25:56 -0800279 pw.println(TAG_OPS + " state:");
Matthew Ng1e43ebd2017-11-14 14:47:05 -0800280 pw.print(" mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
281 pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
282 .isCurrentUserSetup());
283 pw.print(" isConnected="); pw.println(mOverviewProxy != null);
284 }
285
Matthew Ng7d05e772017-11-09 14:41:07 -0800286 public interface OverviewProxyListener {
Winson Chungcbb15a92018-01-25 17:46:16 +0000287 default void onConnectionChanged(boolean isConnected) {}
288 default void onRecentsAnimationStarted() {}
Matthew Ng8f25fb962018-01-16 17:17:24 -0800289 default void onInteractionFlagsChanged(@InteractionType int flags) {}
Matthew Ng7d05e772017-11-09 14:41:07 -0800290 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700291}