1/*
2 * Copyright (C) 2015 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.stackdivider;
18
19import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
20import static android.view.WindowManager.DOCKED_INVALID;
21
22import android.app.ActivityManagerNative;
23import android.graphics.Rect;
24import android.os.RemoteException;
25import android.util.Log;
26import android.view.WindowManagerGlobal;
27
28import com.android.internal.annotations.GuardedBy;
29
30import java.util.concurrent.ExecutorService;
31import java.util.concurrent.Executors;
32
33/**
34 * Proxy to simplify calls into window manager/activity manager
35 */
36public class WindowManagerProxy {
37
38    private static final String TAG = "WindowManagerProxy";
39
40    private static final WindowManagerProxy sInstance = new WindowManagerProxy();
41
42    @GuardedBy("mDockedRect")
43    private final Rect mDockedRect = new Rect();
44    private final Rect mTempDockedTaskRect = new Rect();
45    private final Rect mTempDockedInsetRect = new Rect();
46    private final Rect mTempOtherTaskRect = new Rect();
47    private final Rect mTempOtherInsetRect = new Rect();
48
49    private final Rect mTmpRect1 = new Rect();
50    private final Rect mTmpRect2 = new Rect();
51    private final Rect mTmpRect3 = new Rect();
52    private final Rect mTmpRect4 = new Rect();
53    private final Rect mTmpRect5 = new Rect();
54
55    @GuardedBy("mDockedRect")
56    private final Rect mTouchableRegion = new Rect();
57
58    private boolean mDimLayerVisible;
59    private int mDimLayerTargetStack;
60    private float mDimLayerAlpha;
61
62    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
63
64    private final Runnable mResizeRunnable = new Runnable() {
65        @Override
66        public void run() {
67            synchronized (mDockedRect) {
68                mTmpRect1.set(mDockedRect);
69                mTmpRect2.set(mTempDockedTaskRect);
70                mTmpRect3.set(mTempDockedInsetRect);
71                mTmpRect4.set(mTempOtherTaskRect);
72                mTmpRect5.set(mTempOtherInsetRect);
73            }
74            try {
75                ActivityManagerNative.getDefault()
76                        .resizeDockedStack(mTmpRect1,
77                                mTmpRect2.isEmpty() ? null : mTmpRect2,
78                                mTmpRect3.isEmpty() ? null : mTmpRect3,
79                                mTmpRect4.isEmpty() ? null : mTmpRect4,
80                                mTmpRect5.isEmpty() ? null : mTmpRect5);
81            } catch (RemoteException e) {
82                Log.w(TAG, "Failed to resize stack: " + e);
83            }
84        }
85    };
86
87    private final Runnable mDismissRunnable = new Runnable() {
88        @Override
89        public void run() {
90            try {
91                ActivityManagerNative.getDefault().moveTasksToFullscreenStack(
92                        DOCKED_STACK_ID, false /* onTop */);
93            } catch (RemoteException e) {
94                Log.w(TAG, "Failed to remove stack: " + e);
95            }
96        }
97    };
98
99    private final Runnable mMaximizeRunnable = new Runnable() {
100        @Override
101        public void run() {
102            try {
103                ActivityManagerNative.getDefault().resizeStack(
104                        DOCKED_STACK_ID, null, true, true, false, -1);
105            } catch (RemoteException e) {
106                Log.w(TAG, "Failed to resize stack: " + e);
107            }
108        }
109    };
110
111    private final Runnable mDimLayerRunnable = new Runnable() {
112        @Override
113        public void run() {
114            try {
115                WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible,
116                        mDimLayerTargetStack, mDimLayerAlpha);
117            } catch (RemoteException e) {
118                Log.w(TAG, "Failed to resize stack: " + e);
119            }
120        }
121    };
122
123    private final Runnable mSwapRunnable = new Runnable() {
124        @Override
125        public void run() {
126            try {
127                ActivityManagerNative.getDefault().swapDockedAndFullscreenStack();
128            } catch (RemoteException e) {
129                Log.w(TAG, "Failed to resize stack: " + e);
130            }
131        }
132    };
133
134    private final Runnable mSetTouchableRegionRunnable = new Runnable() {
135        @Override
136        public void run() {
137            try {
138                synchronized (mDockedRect) {
139                    mTmpRect1.set(mTouchableRegion);
140                }
141                WindowManagerGlobal.getWindowManagerService().setDockedStackDividerTouchRegion(
142                        mTmpRect1);
143            } catch (RemoteException e) {
144                Log.w(TAG, "Failed to set touchable region: " + e);
145            }
146        }
147    };
148
149    private WindowManagerProxy() {
150    }
151
152    public static WindowManagerProxy getInstance() {
153        return sInstance;
154    }
155
156    public void resizeDockedStack(Rect docked, Rect tempDockedTaskRect, Rect tempDockedInsetRect,
157            Rect tempOtherTaskRect, Rect tempOtherInsetRect) {
158        synchronized (mDockedRect) {
159            mDockedRect.set(docked);
160            if (tempDockedTaskRect != null) {
161                mTempDockedTaskRect.set(tempDockedTaskRect);
162            } else {
163                mTempDockedTaskRect.setEmpty();
164            }
165            if (tempDockedInsetRect != null) {
166                mTempDockedInsetRect.set(tempDockedInsetRect);
167            } else {
168                mTempDockedInsetRect.setEmpty();
169            }
170            if (tempOtherTaskRect != null) {
171                mTempOtherTaskRect.set(tempOtherTaskRect);
172            } else {
173                mTempOtherTaskRect.setEmpty();
174            }
175            if (tempOtherInsetRect != null) {
176                mTempOtherInsetRect.set(tempOtherInsetRect);
177            } else {
178                mTempOtherInsetRect.setEmpty();
179            }
180        }
181        mExecutor.execute(mResizeRunnable);
182    }
183
184    public void dismissDockedStack() {
185        mExecutor.execute(mDismissRunnable);
186    }
187
188    public void maximizeDockedStack() {
189        mExecutor.execute(mMaximizeRunnable);
190    }
191
192    public void setResizing(final boolean resizing) {
193        mExecutor.execute(new Runnable() {
194            @Override
195            public void run() {
196                try {
197                    WindowManagerGlobal.getWindowManagerService().setDockedStackResizing(resizing);
198                } catch (RemoteException e) {
199                    Log.w(TAG, "Error calling setDockedStackResizing: " + e);
200                }
201            }
202        });
203    }
204
205    public int getDockSide() {
206        try {
207            return WindowManagerGlobal.getWindowManagerService().getDockedStackSide();
208        } catch (RemoteException e) {
209            Log.w(TAG, "Failed to get dock side: " + e);
210        }
211        return DOCKED_INVALID;
212    }
213
214    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
215        mDimLayerVisible = visible;
216        mDimLayerTargetStack = targetStackId;
217        mDimLayerAlpha = alpha;
218        mExecutor.execute(mDimLayerRunnable);
219    }
220
221    public void swapTasks() {
222        mExecutor.execute(mSwapRunnable);
223    }
224
225    public void setTouchRegion(Rect region) {
226        synchronized (mDockedRect) {
227            mTouchableRegion.set(region);
228        }
229        mExecutor.execute(mSetTouchableRegionRunnable);
230    }
231}
232