blob: 0cefe44667747d3a852ae809db9f608153bdd1d5 [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;
28import android.os.RemoteException;
29import android.os.UserHandle;
30import android.util.Log;
Winson Chung38d31c22017-11-08 14:32:32 -080031import android.view.SurfaceControl;
32
33import com.android.systemui.shared.recents.IOverviewProxy;
34import com.android.systemui.shared.recents.ISystemUiProxy;
Matthew Ng7d05e772017-11-09 14:41:07 -080035import com.android.systemui.OverviewProxyService.OverviewProxyListener;
36import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070037import com.android.systemui.statusbar.policy.DeviceProvisionedController;
38import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Matthew Ng7d05e772017-11-09 14:41:07 -080039import java.util.ArrayList;
40import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070041
42/**
43 * Class to send information from overview to launcher with a binder.
44 */
Matthew Ng7d05e772017-11-09 14:41:07 -080045public class OverviewProxyService implements CallbackController<OverviewProxyListener> {
Matthew Ng13dbf872017-10-27 11:02:14 -070046
47 private static final String TAG = "OverviewProxyService";
48 private static final long BACKOFF_MILLIS = 5000;
49
50 private final Context mContext;
51 private final Handler mHandler;
52 private final Runnable mConnectionRunnable = this::startConnectionToCurrentUser;
53 private final DeviceProvisionedController mDeviceProvisionedController
54 = Dependency.get(DeviceProvisionedController.class);
Matthew Ng7d05e772017-11-09 14:41:07 -080055 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Matthew Ng13dbf872017-10-27 11:02:14 -070056
57 private IOverviewProxy mOverviewProxy;
58 private int mConnectionBackoffAttempts;
59
Winson Chung38d31c22017-11-08 14:32:32 -080060 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
61 public Bitmap screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
62 boolean useIdentityTransform, int rotation) {
63 long token = Binder.clearCallingIdentity();
64 try {
65 return SurfaceControl.screenshot(sourceCrop, width, height, minLayer, maxLayer,
66 useIdentityTransform, rotation);
67 } finally {
68 Binder.restoreCallingIdentity(token);
69 }
70 }
71 };
72
Matthew Ng13dbf872017-10-27 11:02:14 -070073 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
74 @Override
75 public void onServiceConnected(ComponentName name, IBinder service) {
76 if (service != null) {
77 mConnectionBackoffAttempts = 0;
78 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
79 // Listen for launcher's death
80 try {
81 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
82 } catch (RemoteException e) {
83 Log.e(TAG, "Lost connection to launcher service", e);
84 }
Winson Chung38d31c22017-11-08 14:32:32 -080085 try {
86 mOverviewProxy.onBind(mSysUiProxy);
87 } catch (RemoteException e) {
88 Log.e(TAG, "Failed to call onBind()", e);
89 }
Matthew Ng7d05e772017-11-09 14:41:07 -080090 notifyConnectionChanged();
Matthew Ng13dbf872017-10-27 11:02:14 -070091 }
92 }
93
94 @Override
95 public void onServiceDisconnected(ComponentName name) {
96 // Do nothing
97 }
98 };
99
100 private final DeviceProvisionedListener mDeviceProvisionedCallback =
101 new DeviceProvisionedListener() {
102 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800103 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700104 if (mDeviceProvisionedController.isCurrentUserSetup()) {
105 startConnectionToCurrentUser();
106 }
107 }
108
109 @Override
110 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700111 mConnectionBackoffAttempts = 0;
112 startConnectionToCurrentUser();
113 }
114 };
115
116 // This is the death handler for the binder from the launcher service
117 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt = new IBinder.DeathRecipient() {
118 @Override
119 public void binderDied() {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800120 startConnectionToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700121 }
122 };
123
124 public OverviewProxyService(Context context) {
125 mContext = context;
126 mHandler = new Handler();
127 mConnectionBackoffAttempts = 0;
128 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
129 }
130
131 public void startConnectionToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800132 disconnectFromLauncherService();
133
Matthew Ng13dbf872017-10-27 11:02:14 -0700134 // If user has not setup yet or already connected, do not try to connect
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800135 if (!mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700136 return;
137 }
138 mHandler.removeCallbacks(mConnectionRunnable);
139 Intent launcherServiceIntent = new Intent();
140 launcherServiceIntent.setComponent(ComponentName.unflattenFromString(
141 mContext.getString(R.string.config_overviewServiceComponent)));
142 boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
143 mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
144 UserHandle.getUserHandleForUid(mDeviceProvisionedController.getCurrentUser()));
145 if (!bound) {
146 // Retry after exponential backoff timeout
147 final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
148 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
149 mConnectionBackoffAttempts++;
150 }
151 }
152
Matthew Ng7d05e772017-11-09 14:41:07 -0800153 @Override
154 public void addCallback(OverviewProxyListener listener) {
155 mConnectionCallbacks.add(listener);
156 listener.onConnectionChanged(mOverviewProxy != null);
157 }
158
159 @Override
160 public void removeCallback(OverviewProxyListener listener) {
161 mConnectionCallbacks.remove(listener);
162 }
163
Matthew Ng13dbf872017-10-27 11:02:14 -0700164 public IOverviewProxy getProxy() {
165 return mOverviewProxy;
166 }
167
168 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800169 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800170 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800171 mContext.unbindService(mOverviewServiceConnection);
172 mOverviewProxy = null;
Matthew Ng7d05e772017-11-09 14:41:07 -0800173 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800174 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700175 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800176
177 private void notifyConnectionChanged() {
178 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
179 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
180 }
181 }
182
183 public interface OverviewProxyListener {
184 void onConnectionChanged(boolean isConnected);
185 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700186}