• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 androidx.window.extensions;
18 
19 import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15;
20 import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
21 
22 import android.app.ActivityThread;
23 import android.app.Application;
24 import android.app.compat.CompatChanges;
25 import android.content.Context;
26 import android.hardware.devicestate.DeviceStateManager;
27 import android.os.SystemProperties;
28 import android.util.Log;
29 
30 import androidx.annotation.NonNull;
31 import androidx.annotation.Nullable;
32 import androidx.annotation.VisibleForTesting;
33 import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
34 import androidx.window.common.RawFoldingFeatureProducer;
35 import androidx.window.extensions.area.WindowAreaComponent;
36 import androidx.window.extensions.area.WindowAreaComponentImpl;
37 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
38 import androidx.window.extensions.embedding.SplitController;
39 import androidx.window.extensions.layout.WindowLayoutComponent;
40 import androidx.window.extensions.layout.WindowLayoutComponentImpl;
41 
42 import com.android.window.flags.Flags;
43 
44 import java.util.Objects;
45 
46 
47 /**
48  * The reference implementation of {@link WindowExtensions} that implements the latest WindowManager
49  * Extensions APIs.
50  */
51 class WindowExtensionsImpl implements WindowExtensions {
52 
53     private static final String TAG = "WindowExtensionsImpl";
54 
55     /**
56      * The value of the system property that indicates no override is set.
57      */
58     private static final int NO_LEVEL_OVERRIDE = -1;
59 
60     private static final int EXTENSIONS_VERSION_V9 = 9;
61 
62     private static final int EXTENSIONS_VERSION_V8 = 8;
63 
64     private static final int EXTENSIONS_VERSION_V7 = 7;
65 
66     private final Object mLock = new Object();
67     private volatile DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer;
68     private volatile WindowLayoutComponentImpl mWindowLayoutComponent;
69     private volatile SplitController mSplitController;
70     private volatile WindowAreaComponent mWindowAreaComponent;
71 
72     private final boolean mIsActivityEmbeddingEnabled;
73 
WindowExtensionsImpl()74     WindowExtensionsImpl() {
75         mIsActivityEmbeddingEnabled = isActivityEmbeddingEnabled();
76 
77         Log.i(TAG, generateLogMessage());
78     }
79 
80     /**
81      * The min version of the WM Extensions that must be supported in the current platform version.
82      */
83     @VisibleForTesting
getExtensionsVersionCurrentPlatform()84     static int getExtensionsVersionCurrentPlatform() {
85         if (Flags.wlinfoOncreate()) {
86             return EXTENSIONS_VERSION_V9;
87         }
88         return EXTENSIONS_VERSION_V8;
89     }
90 
generateLogMessage()91     private String generateLogMessage() {
92         final StringBuilder logBuilder = new StringBuilder("Initializing Window Extensions, "
93                 + "vendor API level=" + getExtensionsVersionCurrentPlatform());
94         final int levelOverride = getLevelOverride();
95         if (levelOverride != NO_LEVEL_OVERRIDE) {
96             logBuilder.append(", override to ").append(levelOverride);
97         }
98         logBuilder.append(", activity embedding enabled=").append(mIsActivityEmbeddingEnabled);
99         return logBuilder.toString();
100     }
101 
102     // TODO(b/241126279) Introduce constants to better version functionality
103     @Override
getVendorApiLevel()104     public int getVendorApiLevel() {
105         final int levelOverride = getLevelOverride();
106         return hasLevelOverride() ? levelOverride : getExtensionsVersionCurrentPlatform();
107     }
108 
109     @VisibleForTesting
hasLevelOverride()110     boolean hasLevelOverride() {
111         return getLevelOverride() != NO_LEVEL_OVERRIDE;
112     }
113 
getLevelOverride()114     private int getLevelOverride() {
115         return SystemProperties.getInt("persist.wm.debug.ext_version_override", NO_LEVEL_OVERRIDE);
116     }
117 
118     @NonNull
getApplication()119     private Application getApplication() {
120         return Objects.requireNonNull(ActivityThread.currentApplication());
121     }
122 
123     @NonNull
getDeviceStateManager()124     private DeviceStateManager getDeviceStateManager() {
125         return Objects.requireNonNull(getApplication().getSystemService(DeviceStateManager.class));
126     }
127 
128     @NonNull
getFoldingFeatureProducer()129     private DeviceStateManagerFoldingFeatureProducer getFoldingFeatureProducer() {
130         if (mFoldingFeatureProducer == null) {
131             synchronized (mLock) {
132                 if (mFoldingFeatureProducer == null) {
133                     final Context context = getApplication();
134                     final RawFoldingFeatureProducer foldingFeatureProducer =
135                             new RawFoldingFeatureProducer(context);
136                     mFoldingFeatureProducer =
137                             new DeviceStateManagerFoldingFeatureProducer(context,
138                                     foldingFeatureProducer, getDeviceStateManager());
139                 }
140             }
141         }
142         return mFoldingFeatureProducer;
143     }
144 
145     @NonNull
getWindowLayoutComponentImpl()146     private WindowLayoutComponentImpl getWindowLayoutComponentImpl() {
147         if (mWindowLayoutComponent == null) {
148             synchronized (mLock) {
149                 if (mWindowLayoutComponent == null) {
150                     final Context context = getApplication();
151                     final DeviceStateManagerFoldingFeatureProducer producer =
152                             getFoldingFeatureProducer();
153                     mWindowLayoutComponent = new WindowLayoutComponentImpl(context, producer);
154                 }
155             }
156         }
157         return mWindowLayoutComponent;
158     }
159 
160     /**
161      * Returns a reference implementation of the latest {@link WindowLayoutComponent}.
162      *
163      * The implementation must match the API level reported in
164      * {@link WindowExtensions#getVendorApiLevel()}.
165      *
166      * @return {@link WindowLayoutComponent} OEM implementation
167      */
168     @NonNull
169     @Override
getWindowLayoutComponent()170     public WindowLayoutComponent getWindowLayoutComponent() {
171         return getWindowLayoutComponentImpl();
172     }
173 
174     /**
175      * Returns a reference implementation of the latest {@link ActivityEmbeddingComponent} if the
176      * device supports this feature, {@code null} otherwise.
177      *
178      * The implementation must match the API level reported in
179      * {@link WindowExtensions#getVendorApiLevel()}.
180      *
181      * @return {@link ActivityEmbeddingComponent} OEM implementation.
182      */
183     @Nullable
184     @Override
getActivityEmbeddingComponent()185     public ActivityEmbeddingComponent getActivityEmbeddingComponent() {
186         if (!mIsActivityEmbeddingEnabled) {
187             return null;
188         }
189         if (mSplitController == null) {
190             synchronized (mLock) {
191                 if (mSplitController == null) {
192                     mSplitController = new SplitController(
193                             getWindowLayoutComponentImpl(),
194                             getFoldingFeatureProducer()
195                     );
196                 }
197             }
198         }
199         return mSplitController;
200     }
201 
202     /**
203      * Returns a reference implementation of the latest {@link WindowAreaComponent}
204      *
205      * The implementation must match the API level reported in
206      * {@link WindowExtensions#getVendorApiLevel()}.
207      *
208      * @return {@link WindowAreaComponent} OEM implementation.
209      */
210     @Nullable
211     @Override
getWindowAreaComponent()212     public WindowAreaComponent getWindowAreaComponent() {
213         if (mWindowAreaComponent == null) {
214             synchronized (mLock) {
215                 if (mWindowAreaComponent == null) {
216                     final Context context = getApplication();
217                     mWindowAreaComponent = new WindowAreaComponentImpl(context);
218                 }
219             }
220         }
221         return mWindowAreaComponent;
222     }
223 
224     @VisibleForTesting
isActivityEmbeddingEnabled()225     static boolean isActivityEmbeddingEnabled() {
226         if (!ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15) {
227             // Device enables it for all apps without targetSDK check.
228             // This must be true for all large screen devices.
229             return true;
230         }
231         // Use compat framework to guard the feature with targetSDK 15.
232         return CompatChanges.isChangeEnabled(ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15);
233     }
234 }
235