1 /*
2  * Copyright (C) 2019 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 package com.android.quickstep;
17 
18 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
19 
20 import android.content.Context;
21 import android.graphics.Bitmap;
22 import android.graphics.Insets;
23 import android.graphics.Rect;
24 import android.os.Bundle;
25 import android.os.IBinder;
26 import android.os.IBinder.DeathRecipient;
27 import android.os.RemoteException;
28 import android.util.Log;
29 import android.view.MotionEvent;
30 
31 import com.android.launcher3.util.MainThreadInitializedObject;
32 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
33 import com.android.systemui.shared.recents.ISystemUiProxy;
34 import com.android.systemui.shared.recents.model.Task;
35 
36 /**
37  * Holds the reference to SystemUI.
38  */
39 public class SystemUiProxy implements ISystemUiProxy {
40     private static final String TAG = SystemUiProxy.class.getSimpleName();
41 
42     public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
43             new MainThreadInitializedObject<>(SystemUiProxy::new);
44 
45     private ISystemUiProxy mSystemUiProxy;
46     private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
47         MAIN_EXECUTOR.execute(() -> setProxy(null));
48     };
49 
50     // Used to dedupe calls to SystemUI
51     private int mLastShelfHeight;
52     private boolean mLastShelfVisible;
53     private float mLastBackButtonAlpha;
54     private boolean mLastBackButtonAnimate;
55 
56     // TODO(141886704): Find a way to remove this
57     private int mLastSystemUiStateFlags;
58 
SystemUiProxy(Context context)59     public SystemUiProxy(Context context) {
60         // Do nothing
61     }
62 
63     @Override
asBinder()64     public IBinder asBinder() {
65         // Do nothing
66         return null;
67     }
68 
setProxy(ISystemUiProxy proxy)69     public void setProxy(ISystemUiProxy proxy) {
70         unlinkToDeath();
71         mSystemUiProxy = proxy;
72         linkToDeath();
73     }
74 
75     // TODO(141886704): Find a way to remove this
setLastSystemUiStateFlags(int stateFlags)76     public void setLastSystemUiStateFlags(int stateFlags) {
77         mLastSystemUiStateFlags = stateFlags;
78     }
79 
80     // TODO(141886704): Find a way to remove this
getLastSystemUiStateFlags()81     public int getLastSystemUiStateFlags() {
82         return mLastSystemUiStateFlags;
83     }
84 
isActive()85     public boolean isActive() {
86         return mSystemUiProxy != null;
87     }
88 
linkToDeath()89     private void linkToDeath() {
90         if (mSystemUiProxy != null) {
91             try {
92                 mSystemUiProxy.asBinder().linkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
93             } catch (RemoteException e) {
94                 Log.e(TAG, "Failed to link sysui proxy death recipient");
95             }
96         }
97     }
98 
unlinkToDeath()99     private void unlinkToDeath() {
100         if (mSystemUiProxy != null) {
101             mSystemUiProxy.asBinder().unlinkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
102         }
103     }
104 
105     @Override
startScreenPinning(int taskId)106     public void startScreenPinning(int taskId) {
107         if (mSystemUiProxy != null) {
108             try {
109                 mSystemUiProxy.startScreenPinning(taskId);
110             } catch (RemoteException e) {
111                 Log.w(TAG, "Failed call startScreenPinning", e);
112             }
113         }
114     }
115 
116     @Override
onSplitScreenInvoked()117     public void onSplitScreenInvoked() {
118         if (mSystemUiProxy != null) {
119             try {
120                 mSystemUiProxy.onSplitScreenInvoked();
121             } catch (RemoteException e) {
122                 Log.w(TAG, "Failed call onSplitScreenInvoked", e);
123             }
124         }
125     }
126 
127     @Override
onOverviewShown(boolean fromHome)128     public void onOverviewShown(boolean fromHome) {
129         onOverviewShown(fromHome, TAG);
130     }
131 
onOverviewShown(boolean fromHome, String tag)132     public void onOverviewShown(boolean fromHome, String tag) {
133         if (mSystemUiProxy != null) {
134             try {
135                 mSystemUiProxy.onOverviewShown(fromHome);
136             } catch (RemoteException e) {
137                 Log.w(tag, "Failed call onOverviewShown from: " + (fromHome ? "home" : "app"), e);
138             }
139         }
140     }
141 
142     @Override
getNonMinimizedSplitScreenSecondaryBounds()143     public Rect getNonMinimizedSplitScreenSecondaryBounds() {
144         if (mSystemUiProxy != null) {
145             try {
146                 return mSystemUiProxy.getNonMinimizedSplitScreenSecondaryBounds();
147             } catch (RemoteException e) {
148                 Log.w(TAG, "Failed call getNonMinimizedSplitScreenSecondaryBounds", e);
149             }
150         }
151         return null;
152     }
153 
154     @Override
setBackButtonAlpha(float alpha, boolean animate)155     public void setBackButtonAlpha(float alpha, boolean animate) {
156         boolean changed = Float.compare(alpha, mLastBackButtonAlpha) != 0
157                 || animate != mLastBackButtonAnimate;
158         if (mSystemUiProxy != null && changed) {
159             mLastBackButtonAlpha = alpha;
160             mLastBackButtonAnimate = animate;
161             try {
162                 mSystemUiProxy.setBackButtonAlpha(alpha, animate);
163             } catch (RemoteException e) {
164                 Log.w(TAG, "Failed call setBackButtonAlpha", e);
165             }
166         }
167     }
168 
getLastBackButtonAlpha()169     public float getLastBackButtonAlpha() {
170         return mLastBackButtonAlpha;
171     }
172 
173     @Override
setNavBarButtonAlpha(float alpha, boolean animate)174     public void setNavBarButtonAlpha(float alpha, boolean animate) {
175         if (mSystemUiProxy != null) {
176             try {
177                 mSystemUiProxy.setNavBarButtonAlpha(alpha, animate);
178             } catch (RemoteException e) {
179                 Log.w(TAG, "Failed call setNavBarButtonAlpha", e);
180             }
181         }
182     }
183 
184     @Override
onStatusBarMotionEvent(MotionEvent event)185     public void onStatusBarMotionEvent(MotionEvent event) {
186         if (mSystemUiProxy != null) {
187             try {
188                 mSystemUiProxy.onStatusBarMotionEvent(event);
189             } catch (RemoteException e) {
190                 Log.w(TAG, "Failed call onStatusBarMotionEvent", e);
191             }
192         }
193     }
194 
195     @Override
onAssistantProgress(float progress)196     public void onAssistantProgress(float progress) {
197         if (mSystemUiProxy != null) {
198             try {
199                 mSystemUiProxy.onAssistantProgress(progress);
200             } catch (RemoteException e) {
201                 Log.w(TAG, "Failed call onAssistantProgress with progress: " + progress, e);
202             }
203         }
204     }
205 
206     @Override
onAssistantGestureCompletion(float velocity)207     public void onAssistantGestureCompletion(float velocity) {
208         if (mSystemUiProxy != null) {
209             try {
210                 mSystemUiProxy.onAssistantGestureCompletion(velocity);
211             } catch (RemoteException e) {
212                 Log.w(TAG, "Failed call onAssistantGestureCompletion", e);
213             }
214         }
215     }
216 
217     @Override
startAssistant(Bundle args)218     public void startAssistant(Bundle args) {
219         if (mSystemUiProxy != null) {
220             try {
221                 mSystemUiProxy.startAssistant(args);
222             } catch (RemoteException e) {
223                 Log.w(TAG, "Failed call startAssistant", e);
224             }
225         }
226     }
227 
228     @Override
monitorGestureInput(String name, int displayId)229     public Bundle monitorGestureInput(String name, int displayId) {
230         if (mSystemUiProxy != null) {
231             try {
232                 return mSystemUiProxy.monitorGestureInput(name, displayId);
233             } catch (RemoteException e) {
234                 Log.w(TAG, "Failed call monitorGestureInput: " + name, e);
235             }
236         }
237         return null;
238     }
239 
240     @Override
notifyAccessibilityButtonClicked(int displayId)241     public void notifyAccessibilityButtonClicked(int displayId) {
242         if (mSystemUiProxy != null) {
243             try {
244                 mSystemUiProxy.notifyAccessibilityButtonClicked(displayId);
245             } catch (RemoteException e) {
246                 Log.w(TAG, "Failed call notifyAccessibilityButtonClicked", e);
247             }
248         }
249     }
250 
251     @Override
notifyAccessibilityButtonLongClicked()252     public void notifyAccessibilityButtonLongClicked() {
253         if (mSystemUiProxy != null) {
254             try {
255                 mSystemUiProxy.notifyAccessibilityButtonLongClicked();
256             } catch (RemoteException e) {
257                 Log.w(TAG, "Failed call notifyAccessibilityButtonLongClicked", e);
258             }
259         }
260     }
261 
262     @Override
stopScreenPinning()263     public void stopScreenPinning() {
264         if (mSystemUiProxy != null) {
265             try {
266                 mSystemUiProxy.stopScreenPinning();
267             } catch (RemoteException e) {
268                 Log.w(TAG, "Failed call stopScreenPinning", e);
269             }
270         }
271     }
272 
273     @Override
setShelfHeight(boolean visible, int shelfHeight)274     public void setShelfHeight(boolean visible, int shelfHeight) {
275         boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight;
276         if (mSystemUiProxy != null && changed) {
277             mLastShelfVisible = visible;
278             mLastShelfHeight = shelfHeight;
279             try {
280                 mSystemUiProxy.setShelfHeight(visible, shelfHeight);
281             } catch (RemoteException e) {
282                 Log.w(TAG, "Failed call setShelfHeight visible: " + visible
283                         + " height: " + shelfHeight, e);
284             }
285         }
286     }
287 
288     @Override
handleImageAsScreenshot(Bitmap bitmap, Rect rect, Insets insets, int i)289     public void handleImageAsScreenshot(Bitmap bitmap, Rect rect, Insets insets, int i) {
290         if (mSystemUiProxy != null) {
291             try {
292                 mSystemUiProxy.handleImageAsScreenshot(bitmap, rect, insets, i);
293             } catch (RemoteException e) {
294                 Log.w(TAG, "Failed call handleImageAsScreenshot", e);
295             }
296         }
297     }
298 
299     @Override
setSplitScreenMinimized(boolean minimized)300     public void setSplitScreenMinimized(boolean minimized) {
301         if (mSystemUiProxy != null) {
302             try {
303                 mSystemUiProxy.setSplitScreenMinimized(minimized);
304             } catch (RemoteException e) {
305                 Log.w(TAG, "Failed call stopScreenPinning", e);
306             }
307         }
308     }
309 
310     /**
311      * Notifies that swipe-to-home action is finished.
312      */
313     @Override
notifySwipeToHomeFinished()314     public void notifySwipeToHomeFinished() {
315         if (mSystemUiProxy != null) {
316             try {
317                 mSystemUiProxy.notifySwipeToHomeFinished();
318             } catch (RemoteException e) {
319                 Log.w(TAG, "Failed call setPinnedStackAnimationType", e);
320             }
321         }
322     }
323 
324     /**
325      * Sets listener to get pinned stack animation callbacks.
326      */
327     @Override
setPinnedStackAnimationListener(IPinnedStackAnimationListener listener)328     public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
329         if (mSystemUiProxy != null) {
330             try {
331                 mSystemUiProxy.setPinnedStackAnimationListener(listener);
332             } catch (RemoteException e) {
333                 Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
334             }
335         }
336     }
337 
338     @Override
onQuickSwitchToNewTask(int rotation)339     public void onQuickSwitchToNewTask(int rotation) {
340         if (mSystemUiProxy != null) {
341             try {
342                 mSystemUiProxy.onQuickSwitchToNewTask(rotation);
343             } catch (RemoteException e) {
344                 Log.w(TAG, "Failed call onQuickSwitchToNewTask with arg: " + rotation, e);
345             }
346         }
347     }
348 
349     @Override
handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen, Insets visibleInsets, Task.TaskKey task)350     public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
351             Insets visibleInsets, Task.TaskKey task) {
352         if (mSystemUiProxy != null) {
353             try {
354                 mSystemUiProxy.handleImageBundleAsScreenshot(screenImageBundle, locationInScreen,
355                         visibleInsets, task);
356             } catch (RemoteException e) {
357                 Log.w(TAG, "Failed call handleImageBundleAsScreenshot");
358             }
359         }
360     }
361 }
362