1 /* <lambda>null2 * 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 package com.android.wallpaper.util 17 18 import android.app.Activity 19 import android.content.Context 20 import android.graphics.Point 21 import android.hardware.display.DisplayManager 22 import android.util.Log 23 import android.view.Display 24 import android.view.Surface.ROTATION_270 25 import android.view.Surface.ROTATION_90 26 27 /** 28 * Utility class to provide methods to find and obtain information about displays via {@link 29 * DisplayManager} 30 */ 31 class DisplayUtils(private val context: Context) { 32 companion object { 33 private const val TAG = "DisplayUtils" 34 private val ROTATION_HORIZONTAL_HINGE = setOf(ROTATION_90, ROTATION_270) 35 } 36 37 private val displayManager: DisplayManager by lazy { 38 context.applicationContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager 39 } 40 41 fun hasMultiInternalDisplays(): Boolean { 42 return getInternalDisplays().size > 1 43 } 44 45 /** 46 * Returns the internal {@link Display} with tthe largest area to be used to calculate wallpaper 47 * size and cropping. 48 */ 49 fun getWallpaperDisplay(): Display { 50 val internalDisplays = getInternalDisplays() 51 return internalDisplays.maxWithOrNull { a, b -> getRealArea(a) - getRealArea(b) } 52 ?: internalDisplays[0] 53 } 54 55 /** 56 * Checks if the device only has one display or unfolded screen in horizontal hinge orientation. 57 */ 58 fun isSingleDisplayOrUnfoldedHorizontalHinge(activity: Activity): Boolean { 59 return !hasMultiInternalDisplays() || isUnfoldedHorizontalHinge(activity) 60 } 61 62 /** 63 * Checks if the device is a foldable and it's unfolded and in horizontal hinge orientation 64 * (portrait). 65 */ 66 fun isUnfoldedHorizontalHinge(activity: Activity): Boolean { 67 return activity.display.rotation in ROTATION_HORIZONTAL_HINGE && 68 isOnWallpaperDisplay(activity) && 69 hasMultiInternalDisplays() 70 } 71 72 fun getMaxDisplaysDimension(): Point { 73 val dimen = Point() 74 getInternalDisplays().let { displays -> 75 dimen.x = displays.maxOf { getRealSize(it).x } 76 dimen.y = displays.maxOf { getRealSize(it).y } 77 } 78 return dimen 79 } 80 81 /** 82 * Returns `true` if the current display is the wallpaper display on a multi-display device. 83 * 84 * On a multi-display device the wallpaper display is the largest display while on a single 85 * display device the only display is both the wallpaper display and the current display. 86 */ 87 fun isOnWallpaperDisplay(activity: Activity): Boolean { 88 return activity.display.uniqueId == getWallpaperDisplay().uniqueId 89 } 90 91 private fun getRealArea(display: Display): Int { 92 val p = Point() 93 display.getRealSize(p) 94 return p.x * p.y 95 } 96 97 private fun getRealSize(display: Display): Point { 98 val p = Point() 99 display.getRealSize(p) 100 return p 101 } 102 103 private fun getInternalDisplays(): List<Display> { 104 val allDisplays: Array<out Display> = 105 displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED) 106 if (allDisplays.isEmpty()) { 107 Log.e(TAG, "No displays found on context ${context.applicationContext}") 108 throw RuntimeException("No displays found!") 109 } 110 return allDisplays.filter { it.type == Display.TYPE_INTERNAL } 111 } 112 } 113