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