blob: fc1c84a7b219a65a03191793cfac2108e471a40f [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.Bitmap;
26import android.graphics.Rect;
Matthew Ng30c0a022017-11-10 14:06:29 -080027import android.net.Uri;
Winson Chung38d31c22017-11-08 14:32:32 -080028import android.os.Binder;
Matthew Ng30c0a022017-11-10 14:06:29 -080029import android.os.Build;
Matthew Ng13dbf872017-10-27 11:02:14 -070030import android.os.Handler;
31import android.os.IBinder;
Matthew Ngfac87832017-11-10 11:27:29 -080032import android.os.Looper;
Matthew Ng30c0a022017-11-10 14:06:29 -080033import android.os.PatternMatcher;
Matthew Ng13dbf872017-10-27 11:02:14 -070034import android.os.RemoteException;
35import android.os.UserHandle;
36import android.util.Log;
Winson Chung38d31c22017-11-08 14:32:32 -080037import android.view.SurfaceControl;
38
39import com.android.systemui.shared.recents.IOverviewProxy;
40import com.android.systemui.shared.recents.ISystemUiProxy;
Matthew Ng7d05e772017-11-09 14:41:07 -080041import com.android.systemui.OverviewProxyService.OverviewProxyListener;
42import com.android.systemui.statusbar.policy.CallbackController;
Matthew Ng13dbf872017-10-27 11:02:14 -070043import com.android.systemui.statusbar.policy.DeviceProvisionedController;
44import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
Matthew Ng7d05e772017-11-09 14:41:07 -080045import java.util.ArrayList;
46import java.util.List;
Matthew Ng13dbf872017-10-27 11:02:14 -070047
48/**
49 * Class to send information from overview to launcher with a binder.
50 */
Matthew Ng7d05e772017-11-09 14:41:07 -080051public class OverviewProxyService implements CallbackController<OverviewProxyListener> {
Matthew Ng13dbf872017-10-27 11:02:14 -070052
53 private static final String TAG = "OverviewProxyService";
54 private static final long BACKOFF_MILLIS = 5000;
55
56 private final Context mContext;
57 private final Handler mHandler;
Matthew Ngfac87832017-11-10 11:27:29 -080058 private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
Matthew Ng30c0a022017-11-10 14:06:29 -080059 private final ComponentName mLauncherComponentName;
Matthew Ng13dbf872017-10-27 11:02:14 -070060 private final DeviceProvisionedController mDeviceProvisionedController
61 = Dependency.get(DeviceProvisionedController.class);
Matthew Ng7d05e772017-11-09 14:41:07 -080062 private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
Matthew Ng13dbf872017-10-27 11:02:14 -070063
64 private IOverviewProxy mOverviewProxy;
65 private int mConnectionBackoffAttempts;
66
Winson Chung38d31c22017-11-08 14:32:32 -080067 private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
68 public Bitmap screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
69 boolean useIdentityTransform, int rotation) {
70 long token = Binder.clearCallingIdentity();
71 try {
72 return SurfaceControl.screenshot(sourceCrop, width, height, minLayer, maxLayer,
73 useIdentityTransform, rotation);
74 } finally {
75 Binder.restoreCallingIdentity(token);
76 }
77 }
78 };
79
Matthew Ng30c0a022017-11-10 14:06:29 -080080 private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
81 @Override
82 public void onReceive(Context context, Intent intent) {
83 // Reconnect immediately, instead of waiting for resume to arrive.
84 startConnectionToCurrentUser();
85 }
86 };
87
Matthew Ng13dbf872017-10-27 11:02:14 -070088 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
89 @Override
90 public void onServiceConnected(ComponentName name, IBinder service) {
91 if (service != null) {
92 mConnectionBackoffAttempts = 0;
93 mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
94 // Listen for launcher's death
95 try {
96 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
97 } catch (RemoteException e) {
98 Log.e(TAG, "Lost connection to launcher service", e);
99 }
Winson Chung38d31c22017-11-08 14:32:32 -0800100 try {
101 mOverviewProxy.onBind(mSysUiProxy);
102 } catch (RemoteException e) {
103 Log.e(TAG, "Failed to call onBind()", e);
104 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800105 notifyConnectionChanged();
Matthew Ng13dbf872017-10-27 11:02:14 -0700106 }
107 }
108
109 @Override
110 public void onServiceDisconnected(ComponentName name) {
111 // Do nothing
112 }
113 };
114
115 private final DeviceProvisionedListener mDeviceProvisionedCallback =
116 new DeviceProvisionedListener() {
117 @Override
Matthew Ngdfab86c2017-11-07 15:46:51 -0800118 public void onUserSetupChanged() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700119 if (mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ngfac87832017-11-10 11:27:29 -0800120 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700121 }
122 }
123
124 @Override
125 public void onUserSwitched() {
Matthew Ng13dbf872017-10-27 11:02:14 -0700126 mConnectionBackoffAttempts = 0;
Matthew Ngfac87832017-11-10 11:27:29 -0800127 internalConnectToCurrentUser();
Matthew Ng13dbf872017-10-27 11:02:14 -0700128 }
129 };
130
131 // This is the death handler for the binder from the launcher service
Matthew Ng30c0a022017-11-10 14:06:29 -0800132 private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
133 = this::startConnectionToCurrentUser;
Matthew Ng13dbf872017-10-27 11:02:14 -0700134
135 public OverviewProxyService(Context context) {
136 mContext = context;
137 mHandler = new Handler();
138 mConnectionBackoffAttempts = 0;
Matthew Ng30c0a022017-11-10 14:06:29 -0800139 mLauncherComponentName = ComponentName
140 .unflattenFromString(context.getString(R.string.config_overviewServiceComponent));
Matthew Ng13dbf872017-10-27 11:02:14 -0700141 mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
Matthew Ng30c0a022017-11-10 14:06:29 -0800142
143 // Listen for the package update changes.
144 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
145 filter.addDataScheme("package");
146 filter.addDataSchemeSpecificPart(mLauncherComponentName.getPackageName(),
147 PatternMatcher.PATTERN_LITERAL);
148 mContext.registerReceiver(mLauncherAddedReceiver, filter);
Matthew Ng13dbf872017-10-27 11:02:14 -0700149 }
150
151 public void startConnectionToCurrentUser() {
Matthew Ngfac87832017-11-10 11:27:29 -0800152 if (mHandler.getLooper() != Looper.myLooper()) {
153 mHandler.post(mConnectionRunnable);
154 } else {
155 internalConnectToCurrentUser();
156 }
157 }
158
159 private void internalConnectToCurrentUser() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800160 disconnectFromLauncherService();
161
Matthew Ng13dbf872017-10-27 11:02:14 -0700162 // If user has not setup yet or already connected, do not try to connect
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800163 if (!mDeviceProvisionedController.isCurrentUserSetup()) {
Matthew Ng13dbf872017-10-27 11:02:14 -0700164 return;
165 }
166 mHandler.removeCallbacks(mConnectionRunnable);
167 Intent launcherServiceIntent = new Intent();
Matthew Ng30c0a022017-11-10 14:06:29 -0800168 launcherServiceIntent.setComponent(mLauncherComponentName);
Matthew Ng13dbf872017-10-27 11:02:14 -0700169 boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
170 mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
171 UserHandle.getUserHandleForUid(mDeviceProvisionedController.getCurrentUser()));
172 if (!bound) {
173 // Retry after exponential backoff timeout
174 final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
175 mHandler.postDelayed(mConnectionRunnable, timeoutMs);
176 mConnectionBackoffAttempts++;
177 }
178 }
179
Matthew Ng7d05e772017-11-09 14:41:07 -0800180 @Override
181 public void addCallback(OverviewProxyListener listener) {
182 mConnectionCallbacks.add(listener);
183 listener.onConnectionChanged(mOverviewProxy != null);
184 }
185
186 @Override
187 public void removeCallback(OverviewProxyListener listener) {
188 mConnectionCallbacks.remove(listener);
189 }
190
Matthew Ng13dbf872017-10-27 11:02:14 -0700191 public IOverviewProxy getProxy() {
192 return mOverviewProxy;
193 }
194
195 private void disconnectFromLauncherService() {
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800196 if (mOverviewProxy != null) {
Matthew Ngeb6893b2017-11-09 17:15:33 -0800197 mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800198 mContext.unbindService(mOverviewServiceConnection);
199 mOverviewProxy = null;
Matthew Ng7d05e772017-11-09 14:41:07 -0800200 notifyConnectionChanged();
Matthew Ng1fa3f7e2017-11-07 11:50:36 -0800201 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700202 }
Matthew Ng7d05e772017-11-09 14:41:07 -0800203
204 private void notifyConnectionChanged() {
205 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
206 mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
207 }
208 }
209
210 public interface OverviewProxyListener {
211 void onConnectionChanged(boolean isConnected);
212 }
Matthew Ng13dbf872017-10-27 11:02:14 -0700213}