1 /* 2 * Copyright (C) 2023 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.area; 18 19 import android.content.Context; 20 import android.hardware.devicestate.DeviceStateRequest; 21 import android.hardware.display.DisplayManager; 22 import android.view.Display; 23 24 import androidx.annotation.NonNull; 25 26 /** 27 * Callback class to be notified of updates to a {@link DeviceStateRequest} for the rear display 28 * presentation state. This class notifies the {@link RearDisplayPresentationController} when the 29 * device is ready to enable the rear display presentation feature. 30 */ 31 public class RearDisplayPresentationRequestCallback implements DeviceStateRequest.Callback { 32 33 private static final String TAG = RearDisplayPresentationRequestCallback.class.getSimpleName(); 34 35 @NonNull 36 private final DisplayManager mDisplayManager; 37 @NonNull 38 private final DisplayManager.DisplayListener mRearDisplayListener = new RearDisplayListener(); 39 @NonNull 40 private final RearDisplayPresentationController mRearDisplayPresentationController; 41 private boolean mWaitingForRearDisplay = false; 42 RearDisplayPresentationRequestCallback(@onNull Context context, @NonNull RearDisplayPresentationController rearDisplayPresentationController)43 public RearDisplayPresentationRequestCallback(@NonNull Context context, 44 @NonNull RearDisplayPresentationController rearDisplayPresentationController) { 45 mDisplayManager = context.getSystemService(DisplayManager.class); 46 mDisplayManager.registerDisplayListener(mRearDisplayListener, 47 context.getMainThreadHandler(), DisplayManager.EVENT_FLAG_DISPLAY_ADDED 48 | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED); 49 50 mRearDisplayPresentationController = rearDisplayPresentationController; 51 } 52 53 @Override onRequestActivated(@onNull DeviceStateRequest request)54 public void onRequestActivated(@NonNull DeviceStateRequest request) { 55 Display[] rearDisplays = mDisplayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_REAR); 56 if (rearDisplays.length == 0) { 57 // No rear facing display found, marking waiting for display flag as true. 58 mWaitingForRearDisplay = true; 59 return; 60 } 61 mDisplayManager.unregisterDisplayListener(mRearDisplayListener); 62 mRearDisplayPresentationController.startSession(rearDisplays[0]); 63 } 64 65 @Override onRequestCanceled(@onNull DeviceStateRequest request)66 public void onRequestCanceled(@NonNull DeviceStateRequest request) { 67 mDisplayManager.unregisterDisplayListener(mRearDisplayListener); 68 mRearDisplayPresentationController.endSession(); 69 } 70 71 /** 72 * {@link DisplayManager.DisplayListener} to be used if a rear facing {@link Display} isn't 73 * available synchronously when the device is entered into the rear display presentation state. 74 * A rear facing {@link Display} is a {@link Display} that is categorized as 75 * {@link DisplayManager#DISPLAY_CATEGORY_REAR}. This can occur if {@link DisplayManager} is 76 * still in the process of configuring itself for this state when 77 * {@link DeviceStateRequest.Callback#onRequestActivated} is called. 78 * 79 * The {@link DisplayManager.DisplayListener} removes itself when a rear facing display is 80 * found. 81 */ 82 private class RearDisplayListener implements DisplayManager.DisplayListener { 83 @Override onDisplayAdded(int displayId)84 public void onDisplayAdded(int displayId) { 85 Display display = mDisplayManager.getDisplay(displayId); 86 if (mWaitingForRearDisplay && (display.getFlags() & Display.FLAG_REAR) != 0) { 87 startRearDisplayPresentation(display); 88 } 89 } 90 91 @Override onDisplayRemoved(int displayId)92 public void onDisplayRemoved(int displayId) {} 93 94 @Override onDisplayChanged(int displayId)95 public void onDisplayChanged(int displayId) { 96 Display display = mDisplayManager.getDisplay(displayId); 97 if (mWaitingForRearDisplay && (display.getFlags() & Display.FLAG_REAR) != 0) { 98 startRearDisplayPresentation(display); 99 } 100 } 101 102 /** 103 * Starts a new {@link RearDisplayPresentation} with the updated {@link Display} with a 104 * category of {@link DisplayManager#DISPLAY_CATEGORY_REAR}. 105 */ startRearDisplayPresentation(Display rearDisplay)106 private void startRearDisplayPresentation(Display rearDisplay) { 107 // We have been notified of a change to a rear display, we can unregister the 108 // callback and stop waiting for a display 109 mDisplayManager.unregisterDisplayListener(this); 110 mWaitingForRearDisplay = false; 111 112 mRearDisplayPresentationController.startSession(rearDisplay); 113 } 114 } 115 } 116