1 /*
2  * Copyright (C) 2018 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 
17 package android.view;
18 
19 import android.annotation.IntDef;
20 import android.annotation.Nullable;
21 import android.view.InsetsState.InternalInsetType;
22 import android.view.SurfaceControl.Transaction;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.util.function.Supplier;
29 
30 /**
31  * Controls the visibility and animations of a single window insets source.
32  * @hide
33  */
34 public class InsetsSourceConsumer {
35 
36     @Retention(RetentionPolicy.SOURCE)
37     @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.SHOW_DELAYED, ShowResult.SHOW_FAILED})
38     @interface ShowResult {
39         /**
40          * Window type is ready to be shown, will be shown immidiately.
41          */
42         int SHOW_IMMEDIATELY = 0;
43         /**
44          * Result will be delayed. Window needs to be prepared or request is not from controller.
45          * Request will be delegated to controller and may or may not be shown.
46          */
47         int SHOW_DELAYED = 1;
48         /**
49          * Window will not be shown because one of the conditions couldn't be met.
50          * (e.g. in IME's case, when no editor is focused.)
51          */
52         int SHOW_FAILED = 2;
53     }
54 
55     protected final InsetsController mController;
56     protected boolean mVisible;
57     private final Supplier<Transaction> mTransactionSupplier;
58     private final @InternalInsetType int mType;
59     private final InsetsState mState;
60     private @Nullable InsetsSourceControl mSourceControl;
61 
InsetsSourceConsumer(@nternalInsetType int type, InsetsState state, Supplier<Transaction> transactionSupplier, InsetsController controller)62     public InsetsSourceConsumer(@InternalInsetType int type, InsetsState state,
63             Supplier<Transaction> transactionSupplier, InsetsController controller) {
64         mType = type;
65         mState = state;
66         mTransactionSupplier = transactionSupplier;
67         mController = controller;
68         mVisible = InsetsState.getDefaultVisibility(type);
69     }
70 
setControl(@ullable InsetsSourceControl control)71     public void setControl(@Nullable InsetsSourceControl control) {
72         if (mSourceControl == control) {
73             return;
74         }
75         mSourceControl = control;
76         applyHiddenToControl();
77         if (applyLocalVisibilityOverride()) {
78             mController.notifyVisibilityChanged();
79         }
80         if (mSourceControl == null) {
81             mController.notifyControlRevoked(this);
82         }
83     }
84 
85     @VisibleForTesting
getControl()86     public InsetsSourceControl getControl() {
87         return mSourceControl;
88     }
89 
getType()90     int getType() {
91         return mType;
92     }
93 
94     @VisibleForTesting
show()95     public void show() {
96         setVisible(true);
97     }
98 
99     @VisibleForTesting
hide()100     public void hide() {
101         setVisible(false);
102     }
103 
104     /**
105      * Called when current window gains focus
106      */
onWindowFocusGained()107     public void onWindowFocusGained() {}
108 
109     /**
110      * Called when current window loses focus.
111      */
onWindowFocusLost()112     public void onWindowFocusLost() {}
113 
applyLocalVisibilityOverride()114     boolean applyLocalVisibilityOverride() {
115 
116         // If we don't have control, we are not able to change the visibility.
117         if (mSourceControl == null) {
118             return false;
119         }
120         if (mState.getSource(mType).isVisible() == mVisible) {
121             return false;
122         }
123         mState.getSource(mType).setVisible(mVisible);
124         return true;
125     }
126 
127     @VisibleForTesting
isVisible()128     public boolean isVisible() {
129         return mVisible;
130     }
131 
132     /**
133      * Request to show current window type.
134      *
135      * @param fromController {@code true} if request is coming from controller.
136      *                       (e.g. in IME case, controller is
137      *                       {@link android.inputmethodservice.InputMethodService}).
138      * @return @see {@link ShowResult}.
139      */
requestShow(boolean fromController)140     @ShowResult int requestShow(boolean fromController) {
141         return ShowResult.SHOW_IMMEDIATELY;
142     }
143 
144     /**
145      * Notify listeners that window is now hidden.
146      */
notifyHidden()147     void notifyHidden() {
148         // no-op for types that always return ShowResult#SHOW_IMMEDIATELY.
149     }
150 
setVisible(boolean visible)151     private void setVisible(boolean visible) {
152         if (mVisible == visible) {
153             return;
154         }
155         mVisible = visible;
156         applyHiddenToControl();
157         applyLocalVisibilityOverride();
158         mController.notifyVisibilityChanged();
159     }
160 
applyHiddenToControl()161     private void applyHiddenToControl() {
162         if (mSourceControl == null) {
163             return;
164         }
165 
166         final Transaction t = mTransactionSupplier.get();
167         if (mVisible) {
168             t.show(mSourceControl.getLeash());
169         } else {
170             t.hide(mSourceControl.getLeash());
171         }
172         t.apply();
173     }
174 }
175