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.Display.DEFAULT_DISPLAY; 20 21 import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation; 22 import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect; 23 24 import android.app.Activity; 25 import android.content.Context; 26 import android.graphics.Rect; 27 import android.util.Log; 28 29 import androidx.annotation.NonNull; 30 import androidx.window.common.DeviceStateManagerPostureProducer; 31 import androidx.window.common.DisplayFeature; 32 import androidx.window.common.ResourceConfigDisplayFeatureProducer; 33 import androidx.window.common.SettingsDevicePostureProducer; 34 import androidx.window.common.SettingsDisplayFeatureProducer; 35 import androidx.window.util.DataProducer; 36 import androidx.window.util.PriorityDataProducer; 37 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Optional; 41 42 /** 43 * Reference implementation of androidx.window.extensions OEM interface for use with 44 * WindowManager Jetpack. 45 * 46 * NOTE: This version is a work in progress and under active development. It MUST NOT be used in 47 * production builds since the interface can still change before reaching stable version. 48 * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead. 49 */ 50 class SampleExtensionImpl extends StubExtension { 51 private static final String TAG = "SampleExtension"; 52 53 private final SettingsDevicePostureProducer mSettingsDevicePostureProducer; 54 private final DataProducer<Integer> mDevicePostureProducer; 55 56 private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer; 57 private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer; 58 SampleExtensionImpl(Context context)59 SampleExtensionImpl(Context context) { 60 mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context); 61 mDevicePostureProducer = new PriorityDataProducer<>(List.of( 62 mSettingsDevicePostureProducer, 63 new DeviceStateManagerPostureProducer(context) 64 )); 65 66 mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context); 67 mDisplayFeatureProducer = new PriorityDataProducer<>(List.of( 68 mSettingsDisplayFeatureProducer, 69 new ResourceConfigDisplayFeatureProducer(context) 70 )); 71 72 mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); 73 mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); 74 } 75 getFeatureState(DisplayFeature feature)76 private int getFeatureState(DisplayFeature feature) { 77 Integer featureState = feature.getState(); 78 Optional<Integer> posture = mDevicePostureProducer.getData(); 79 int fallbackPosture = posture.orElse(ExtensionFoldingFeature.STATE_FLAT); 80 return featureState == null ? fallbackPosture : featureState; 81 } 82 onDisplayFeaturesChanged()83 private void onDisplayFeaturesChanged() { 84 for (Activity activity : getActivitiesListeningForLayoutChanges()) { 85 ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(activity); 86 updateWindowLayout(activity, newLayout); 87 } 88 } 89 90 @NonNull getWindowLayoutInfo(@onNull Activity activity)91 private ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) { 92 List<ExtensionDisplayFeature> displayFeatures = getDisplayFeatures(activity); 93 return new ExtensionWindowLayoutInfo(displayFeatures); 94 } 95 getDisplayFeatures(@onNull Activity activity)96 private List<ExtensionDisplayFeature> getDisplayFeatures(@NonNull Activity activity) { 97 List<ExtensionDisplayFeature> features = new ArrayList<>(); 98 int displayId = activity.getDisplay().getDisplayId(); 99 if (displayId != DEFAULT_DISPLAY) { 100 Log.w(TAG, "This sample doesn't support display features on secondary displays"); 101 return features; 102 } 103 104 if (activity.isInMultiWindowMode()) { 105 // It is recommended not to report any display features in multi-window mode, since it 106 // won't be possible to synchronize the display feature positions with window movement. 107 return features; 108 } 109 110 Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData(); 111 if (storedFeatures.isPresent()) { 112 113 for (DisplayFeature baseFeature : storedFeatures.get()) { 114 Rect featureRect = baseFeature.getRect(); 115 rotateRectToDisplayRotation(displayId, featureRect); 116 transformToWindowSpaceRect(activity, featureRect); 117 118 features.add(new ExtensionFoldingFeature(featureRect, baseFeature.getType(), 119 getFeatureState(baseFeature))); 120 } 121 } 122 return features; 123 } 124 125 @Override onListenersChanged()126 protected void onListenersChanged() { 127 if (hasListeners()) { 128 mSettingsDevicePostureProducer.registerObserversIfNeeded(); 129 mSettingsDisplayFeatureProducer.registerObserversIfNeeded(); 130 } else { 131 mSettingsDevicePostureProducer.unregisterObserversIfNeeded(); 132 mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded(); 133 } 134 135 onDisplayFeaturesChanged(); 136 } 137 } 138