/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher3.util; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.content.Context; import android.graphics.Point; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Handler; import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.WindowManager; import java.util.ArrayList; /** * Utility class to cache properties of default display to avoid a system RPC on every call. */ public class DefaultDisplay implements DisplayListener { public static final MainThreadInitializedObject INSTANCE = new MainThreadInitializedObject<>(DefaultDisplay::new); private static final String TAG = "DefaultDisplay"; public static final int CHANGE_SIZE = 1 << 0; public static final int CHANGE_ROTATION = 1 << 1; public static final int CHANGE_FRAME_DELAY = 1 << 2; private final Context mContext; private final int mId; private final ArrayList mListeners = new ArrayList<>(); private final Handler mChangeHandler; private Info mInfo; private DefaultDisplay(Context context) { mContext = context; mInfo = new Info(context); mId = mInfo.id; mChangeHandler = new Handler(this::onChange); context.getSystemService(DisplayManager.class) .registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler()); } @Override public final void onDisplayAdded(int displayId) { } @Override public final void onDisplayRemoved(int displayId) { } @Override public final void onDisplayChanged(int displayId) { if (displayId != mId) { return; } Info oldInfo = mInfo; Info info = new Info(mContext); int change = 0; if (info.hasDifferentSize(oldInfo)) { change |= CHANGE_SIZE; } if (oldInfo.rotation != info.rotation) { change |= CHANGE_ROTATION; } if (info.singleFrameMs != oldInfo.singleFrameMs) { change |= CHANGE_FRAME_DELAY; } if (change != 0) { mInfo = info; mChangeHandler.sendEmptyMessage(change); } } public static int getSingleFrameMs(Context context) { return INSTANCE.get(context).getInfo().singleFrameMs; } public Info getInfo() { return mInfo; } public void addChangeListener(DisplayInfoChangeListener listener) { mListeners.add(listener); } public void removeChangeListener(DisplayInfoChangeListener listener) { mListeners.remove(listener); } private boolean onChange(Message msg) { for (int i = mListeners.size() - 1; i >= 0; i--) { mListeners.get(i).onDisplayInfoChanged(mInfo, msg.what); } return true; } public static class Info { public final int id; public final int rotation; public final int singleFrameMs; public final Point realSize; public final Point smallestSize; public final Point largestSize; public final DisplayMetrics metrics; private Info(Context context) { Display display = context.getSystemService(WindowManager.class).getDefaultDisplay(); id = display.getDisplayId(); rotation = display.getRotation(); float refreshRate = display.getRefreshRate(); singleFrameMs = refreshRate > 0 ? (int) (1000 / refreshRate) : 16; realSize = new Point(); smallestSize = new Point(); largestSize = new Point(); display.getRealSize(realSize); display.getCurrentSizeRange(smallestSize, largestSize); metrics = new DisplayMetrics(); display.getMetrics(metrics); } private boolean hasDifferentSize(Info info) { if (!realSize.equals(info.realSize) && !realSize.equals(info.realSize.y, info.realSize.x)) { Log.d(TAG, String.format("Display size changed from %s to %s", info.realSize, realSize)); return true; } if (!smallestSize.equals(info.smallestSize) || !largestSize.equals(info.largestSize)) { Log.d(TAG, String.format("Available size changed from [%s, %s] to [%s, %s]", smallestSize, largestSize, info.smallestSize, info.largestSize)); return true; } return false; } } /** * Interface for listening for display changes */ public interface DisplayInfoChangeListener { void onDisplayInfoChanged(Info info, int flags); } }