blob: 039e13c41e9a69e8a10709365743d2f73b705d16 [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
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.ServiceConnection;
Winson Chung38d31c22017-11-08 14:32:32 -080023import android.graphics.Bitmap;
24import android.graphics.Rect;
25import android.os.Binder;
Matthew Ng13dbf872017-10-27 11:02:14 -070026import android.os.Handler;
27import android.os.IBinder;
Matthew Ngfac87832017-11-10 11:27:29 -080028import android.os.Looper;
Matthew Ng13dbf872017-10-27 11:02:14 -070029import android.os.RemoteException;
30import android.os.UserHandle;
31import android.util.Log;
Winson Chung38d31c22017-11-08 14:32:32 -080032import android.view.SurfaceControl;
33
34import com.android.systemui.shared.recents.IOverviewProxy;
35import com.android.systemui.shared.recents.ISystemUiProxy;
Matthew Ng7d05e772017-11-09 14:41:07 -080036import com.android.systemui.OverviewProxyService.OverviewProxyListener;
37import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070038import com.android.systemui.statusbar.policy.DeviceProvisionedController;
39import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Matthew Ng7d05e772017-11-09 14:41:07 -080040import java.util.ArrayList;
41import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070042
43/**
44 * Class to send information from overview to launcher with a binder.
45 */
Matthew Ng7d05e772017-11-09 14:41:07 -080046public class OverviewProxyService implements CallbackController<OverviewProxyListener> {
Matthew Ng13dbf872017-10-27 11:02:14 -070047
48 private static final String TAG = "OverviewProxyService";
49 private static final long BACKOFF_MILLIS = 5000;
50
51 private final Context mContext;
52 private final Handler mHandler;
Matthew Ngfac87832017-11-10 11:27:29 -080053 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
Matthew Ng13dbf872017-10-27 11:02:14 -070054 private final DeviceProvisionedController mDeviceProvisionedController
55 = Dependency.get(DeviceProvisionedController.class);
Matthew Ng7d05e772017-11-09 14:41:07 -080056 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Matthew Ng13dbf872017-10-27 11:02:14 -070057
58 private IOverviewProxy mOverviewProxy;
59 private int mConnectionBackoffAttempts;
60
Winson Chung38d31c22017-11-08 14:32:32 -080061 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
62 public Bitmap screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
63 boolean useIdentityTransform, int rotation) {
64 long token = Binder.clearCallingIdentity();
65 try {
66 return SurfaceControl.screenshot(sourceCrop, width, height, minLayer, maxLayer,
67 useIdentityTransform, rotation);
68 } finally {
69 Binder.restoreCallingIdentity(token);
70 }
71 }
72 };
73
Matthew Ng13dbf872017-10-27 11:02:14 -070074 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
75 @Override
76 public void onServiceConnected(ComponentName name, IBinder service) {
77 if (service != null) {
78 mConnectionBackoffAttempts = 0;
79 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
80 // Listen for launcher's death
81 try {
82 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
83 } catch (RemoteException e) {
84 Log.e(TAG, "Lost connection to launcher service", e);
85 }
Winson Chung38d31c22017-11-08 14:32:32 -080086 try {
87 mOverviewProxy.onBind(mSysUiProxy);
88 } catch (RemoteException e) {
89 Log.e(TAG, "Failed to call onBind()", e);
90 }
Matthew Ng7d05e772017-11-09 14:41:07 -080091 notifyConnectionChanged();
Matthew Ng13dbf872017-10-27 11:02:14 -070092 }
93 }
94
95 @Override
96 public void onServiceDisconnected(ComponentName name) {
97 // Do nothing
98 }
99 };
100
101 private final DeviceProvisionedListener mDeviceProvisionedCallback =
102 new DeviceProvisionedListener() {
103 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800104 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700105 if (mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ngfac87832017-11-10 11:27:29 -0800106 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700107 }
108 }
109
110 @Override
111 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700112 mConnectionBackoffAttempts = 0;
Matthew Ngfac87832017-11-10 11:27:29 -0800113 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700114 }
115 };
116
117 // This is the death handler for the binder from the launcher service
118 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt = new IBinder.DeathRecipient() {
119 @Override
120 public void binderDied() {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800121 startConnectionToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700122 }
123 };
124
125 public OverviewProxyService(Context context) {
126 mContext = context;
127 mHandler = new Handler();
128 mConnectionBackoffAttempts = 0;
129 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
130 }
131
132 public void startConnectionToCurrentUser() {
Matthew Ngfac87832017-11-10 11:27:29 -0800133 if (mHandler.getLooper() != Looper.myLooper()) {
134 mHandler.post(mConnectionRunnable);
135 } else {
136 internalConnectToCurrentUser();
137 }
138 }
139
140 private void internalConnectToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800141 disconnectFromLauncherService();
142
Matthew Ng13dbf872017-10-27 11:02:14 -0700143 // If user has not setup yet or already connected, do not try to connect
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800144 if (!mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700145 return;
146 }
147 mHandler.removeCallbacks(mConnectionRunnable);
148 Intent launcherServiceIntent = new Intent();
149 launcherServiceIntent.setComponent(ComponentName.unflattenFromString(
150 mContext.getString(R.string.config_overviewServiceComponent)));
151 boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
152 mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
153 UserHandle.getUserHandleForUid(mDeviceProvisionedController.getCurrentUser()));
154 if (!bound) {
155 // Retry after exponential backoff timeout
156 final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
157 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
158 mConnectionBackoffAttempts++;
159 }
160 }
161
Matthew Ng7d05e772017-11-09 14:41:07 -0800162 @Override
163 public void addCallback(OverviewProxyListener listener) {
164 mConnectionCallbacks.add(listener);
165 listener.onConnectionChanged(mOverviewProxy != null);
166 }
167
168 @Override
169 public void removeCallback(OverviewProxyListener listener) {
170 mConnectionCallbacks.remove(listener);
171 }
172
Matthew Ng13dbf872017-10-27 11:02:14 -0700173 public IOverviewProxy getProxy() {
174 return mOverviewProxy;
175 }
176
177 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800178 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800179 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800180 mContext.unbindService(mOverviewServiceConnection);
181 mOverviewProxy = null;
Matthew Ng7d05e772017-11-09 14:41:07 -0800182 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800183 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700184 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800185
186 private void notifyConnectionChanged() {
187 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
188 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
189 }
190 }
191
192 public interface OverviewProxyListener {
193 void onConnectionChanged(boolean isConnected);
194 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700195}