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 android.content.res.Configuration;
20import android.os.RemoteException;
21import android.view.IDockedStackListener;
22import android.view.LayoutInflater;
23import android.view.View;
24
25import com.android.systemui.R;
26import com.android.systemui.SystemUI;
27import com.android.systemui.recents.Recents;
28import com.android.systemui.recents.misc.SystemServicesProxy;
29
30import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
31import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
32
33import java.io.FileDescriptor;
34import java.io.PrintWriter;
35
36/**
37 * Controls the docked stack divider.
38 */
39public class Divider extends SystemUI {
40    private DividerWindowManager mWindowManager;
41    private DividerView mView;
42    private final DividerState mDividerState = new DividerState();
43    private DockDividerVisibilityListener mDockDividerVisibilityListener;
44    private boolean mVisible = false;
45    private boolean mMinimized = false;
46    private boolean mAdjustedForIme = false;
47    private ForcedResizableInfoActivityController mForcedResizableController;
48
49    @Override
50    public void start() {
51        mWindowManager = new DividerWindowManager(mContext);
52        update(mContext.getResources().getConfiguration());
53        putComponent(Divider.class, this);
54        mDockDividerVisibilityListener = new DockDividerVisibilityListener();
55        SystemServicesProxy ssp = Recents.getSystemServices();
56        ssp.registerDockedStackListener(mDockDividerVisibilityListener);
57        mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
58    }
59
60    @Override
61    protected void onConfigurationChanged(Configuration newConfig) {
62        super.onConfigurationChanged(newConfig);
63        update(newConfig);
64    }
65
66    public DividerView getView() {
67        return mView;
68    }
69
70    private void addDivider(Configuration configuration) {
71        mView = (DividerView)
72                LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
73        mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
74        final int size = mContext.getResources().getDimensionPixelSize(
75                com.android.internal.R.dimen.docked_stack_divider_thickness);
76        final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
77        final int width = landscape ? size : MATCH_PARENT;
78        final int height = landscape ? MATCH_PARENT : size;
79        mWindowManager.add(mView, width, height);
80        mView.injectDependencies(mWindowManager, mDividerState);
81    }
82
83    private void removeDivider() {
84        mWindowManager.remove();
85    }
86
87    private void update(Configuration configuration) {
88        removeDivider();
89        addDivider(configuration);
90        if (mMinimized) {
91            mView.setMinimizedDockStack(true);
92            updateTouchable();
93        }
94    }
95
96    private void updateVisibility(final boolean visible) {
97        mView.post(new Runnable() {
98            @Override
99            public void run() {
100                if (mVisible != visible) {
101                    mVisible = visible;
102                    mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
103
104                    // Update state because animations won't finish.
105                    mView.setMinimizedDockStack(mMinimized);
106                }
107            }
108        });
109    }
110
111    private void updateMinimizedDockedStack(final boolean minimized, final long animDuration) {
112        mView.post(new Runnable() {
113            @Override
114            public void run() {
115                if (mMinimized != minimized) {
116                    mMinimized = minimized;
117                    updateTouchable();
118                    if (animDuration > 0) {
119                        mView.setMinimizedDockStack(minimized, animDuration);
120                    } else {
121                        mView.setMinimizedDockStack(minimized);
122                    }
123                }
124            }
125        });
126    }
127
128    private void notifyDockedStackExistsChanged(final boolean exists) {
129        mView.post(new Runnable() {
130            @Override
131            public void run() {
132                mForcedResizableController.notifyDockedStackExistsChanged(exists);
133            }
134        });
135    }
136
137    private void updateTouchable() {
138        mWindowManager.setTouchable(!mMinimized && !mAdjustedForIme);
139    }
140
141    @Override
142    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
143        pw.print("  mVisible="); pw.println(mVisible);
144        pw.print("  mMinimized="); pw.println(mMinimized);
145        pw.print("  mAdjustedForIme="); pw.println(mAdjustedForIme);
146    }
147
148    class DockDividerVisibilityListener extends IDockedStackListener.Stub {
149
150        @Override
151        public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
152            updateVisibility(visible);
153        }
154
155        @Override
156        public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
157            notifyDockedStackExistsChanged(exists);
158        }
159
160        @Override
161        public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
162                throws RemoteException {
163            updateMinimizedDockedStack(minimized, animDuration);
164        }
165
166        @Override
167        public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
168                throws RemoteException {
169            mView.post(() -> {
170                if (mAdjustedForIme != adjustedForIme) {
171                    mAdjustedForIme = adjustedForIme;
172                    updateTouchable();
173                    if (!mMinimized) {
174                        if (animDuration > 0) {
175                            mView.setAdjustedForIme(adjustedForIme, animDuration);
176                        } else {
177                            mView.setAdjustedForIme(adjustedForIme);
178                        }
179                    }
180                }
181            });
182        }
183
184        @Override
185        public void onDockSideChanged(final int newDockSide) throws RemoteException {
186            mView.post(() -> mView.notifyDockSideChanged(newDockSide));
187        }
188    }
189}
190