1 /* 2 * Copyright (C) 2020 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.sidecar; 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.app.ActivityThread; 26 import android.content.Context; 27 import android.graphics.Rect; 28 import android.os.IBinder; 29 import android.util.Log; 30 31 import androidx.annotation.NonNull; 32 import androidx.window.common.DeviceStateManagerPostureProducer; 33 import androidx.window.common.DisplayFeature; 34 import androidx.window.common.ResourceConfigDisplayFeatureProducer; 35 import androidx.window.common.SettingsDevicePostureProducer; 36 import androidx.window.common.SettingsDisplayFeatureProducer; 37 import androidx.window.util.DataProducer; 38 import androidx.window.util.PriorityDataProducer; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.Optional; 43 44 /** 45 * Reference implementation of androidx.window.sidecar OEM interface for use with 46 * WindowManager Jetpack. 47 */ 48 class SampleSidecarImpl extends StubSidecar { 49 private static final String TAG = "SampleSidecar"; 50 51 private final SettingsDevicePostureProducer mSettingsDevicePostureProducer; 52 private final DataProducer<Integer> mDevicePostureProducer; 53 54 private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer; 55 private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer; 56 SampleSidecarImpl(Context context)57 SampleSidecarImpl(Context context) { 58 mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context); 59 mDevicePostureProducer = new PriorityDataProducer<>(List.of( 60 mSettingsDevicePostureProducer, 61 new DeviceStateManagerPostureProducer(context) 62 )); 63 64 mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context); 65 mDisplayFeatureProducer = new PriorityDataProducer<>(List.of( 66 mSettingsDisplayFeatureProducer, 67 new ResourceConfigDisplayFeatureProducer(context) 68 )); 69 70 mDevicePostureProducer.addDataChangedCallback(this::onDevicePostureChanged); 71 mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); 72 } 73 onDevicePostureChanged()74 private void onDevicePostureChanged() { 75 updateDeviceState(getDeviceState()); 76 } 77 onDisplayFeaturesChanged()78 private void onDisplayFeaturesChanged() { 79 for (IBinder windowToken : getWindowsListeningForLayoutChanges()) { 80 SidecarWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken); 81 updateWindowLayout(windowToken, newLayout); 82 } 83 } 84 85 @NonNull 86 @Override getDeviceState()87 public SidecarDeviceState getDeviceState() { 88 Optional<Integer> posture = mDevicePostureProducer.getData(); 89 90 SidecarDeviceState deviceState = new SidecarDeviceState(); 91 deviceState.posture = posture.orElse(SidecarDeviceState.POSTURE_UNKNOWN); 92 return deviceState; 93 } 94 95 @NonNull 96 @Override getWindowLayoutInfo(@onNull IBinder windowToken)97 public SidecarWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) { 98 Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken); 99 SidecarWindowLayoutInfo windowLayoutInfo = new SidecarWindowLayoutInfo(); 100 if (activity == null) { 101 return windowLayoutInfo; 102 } 103 windowLayoutInfo.displayFeatures = getDisplayFeatures(activity); 104 return windowLayoutInfo; 105 } 106 getDisplayFeatures(@onNull Activity activity)107 private List<SidecarDisplayFeature> getDisplayFeatures(@NonNull Activity activity) { 108 List<SidecarDisplayFeature> features = new ArrayList<SidecarDisplayFeature>(); 109 int displayId = activity.getDisplay().getDisplayId(); 110 if (displayId != DEFAULT_DISPLAY) { 111 Log.w(TAG, "This sample doesn't support display features on secondary displays"); 112 return features; 113 } 114 115 if (activity.isInMultiWindowMode()) { 116 // It is recommended not to report any display features in multi-window mode, since it 117 // won't be possible to synchronize the display feature positions with window movement. 118 return features; 119 } 120 121 Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData(); 122 if (storedFeatures.isPresent()) { 123 for (DisplayFeature baseFeature : storedFeatures.get()) { 124 SidecarDisplayFeature feature = new SidecarDisplayFeature(); 125 Rect featureRect = baseFeature.getRect(); 126 rotateRectToDisplayRotation(displayId, featureRect); 127 transformToWindowSpaceRect(activity, featureRect); 128 feature.setRect(featureRect); 129 feature.setType(baseFeature.getType()); 130 features.add(feature); 131 } 132 } 133 return features; 134 } 135 136 @Override onListenersChanged()137 protected void onListenersChanged() { 138 if (hasListeners()) { 139 mSettingsDevicePostureProducer.registerObserversIfNeeded(); 140 mSettingsDisplayFeatureProducer.registerObserversIfNeeded(); 141 } else { 142 mSettingsDevicePostureProducer.unregisterObserversIfNeeded(); 143 mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded(); 144 } 145 } 146 } 147