• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.launcher3.util;
2 
3 /**
4  * Copyright (C) 2015 The Android Open Source Project
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.res.Configuration;
24 import android.graphics.Point;
25 import android.hardware.display.DisplayManager;
26 import android.hardware.display.DisplayManager.DisplayListener;
27 import android.os.Handler;
28 import android.util.Log;
29 import android.view.Display;
30 import android.view.WindowManager;
31 
32 import com.android.launcher3.MainThreadExecutor;
33 
34 import java.util.function.Consumer;
35 
36 /**
37  * {@link BroadcastReceiver} which watches configuration changes and
38  * notifies the callback in case changes which affect the device profile occur.
39  */
40 public class ConfigMonitor extends BroadcastReceiver implements DisplayListener {
41 
42     private static final String TAG = "ConfigMonitor";
43 
44     private final Point mTmpPoint1 = new Point();
45     private final Point mTmpPoint2 = new Point();
46 
47     private final Context mContext;
48     private final float mFontScale;
49     private final int mDensity;
50 
51     private final int mDisplayId;
52     private final Point mRealSize;
53     private final Point mSmallestSize, mLargestSize;
54 
55     private Consumer<Context> mCallback;
56 
ConfigMonitor(Context context, Consumer<Context> callback)57     public ConfigMonitor(Context context, Consumer<Context> callback) {
58         mContext = context;
59 
60         Configuration config = context.getResources().getConfiguration();
61         mFontScale = config.fontScale;
62         mDensity = config.densityDpi;
63 
64         Display display = getDefaultDisplay(context);
65         mDisplayId = display.getDisplayId();
66 
67         mRealSize = new Point();
68         display.getRealSize(mRealSize);
69 
70         mSmallestSize = new Point();
71         mLargestSize = new Point();
72         display.getCurrentSizeRange(mSmallestSize, mLargestSize);
73 
74         mCallback = callback;
75 
76         // Listen for configuration change
77         mContext.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
78 
79         // Listen for display manager change
80         mContext.getSystemService(DisplayManager.class)
81                 .registerDisplayListener(this, new Handler(UiThreadHelper.getBackgroundLooper()));
82     }
83 
84     @Override
onReceive(Context context, Intent intent)85     public void onReceive(Context context, Intent intent) {
86         Configuration config = context.getResources().getConfiguration();
87         if (mFontScale != config.fontScale || mDensity != config.densityDpi) {
88             Log.d(TAG, "Configuration changed.");
89             notifyChange();
90         }
91     }
92 
93     @Override
onDisplayAdded(int displayId)94     public void onDisplayAdded(int displayId) { }
95 
96     @Override
onDisplayRemoved(int displayId)97     public void onDisplayRemoved(int displayId) { }
98 
99     @Override
onDisplayChanged(int displayId)100     public void onDisplayChanged(int displayId) {
101         if (displayId != mDisplayId) {
102             return;
103         }
104         Display display = getDefaultDisplay(mContext);
105         display.getRealSize(mTmpPoint1);
106 
107         if (!mRealSize.equals(mTmpPoint1) && !mRealSize.equals(mTmpPoint1.y, mTmpPoint1.x)) {
108             Log.d(TAG, String.format("Display size changed from %s to %s", mRealSize, mTmpPoint1));
109             notifyChange();
110             return;
111         }
112 
113         display.getCurrentSizeRange(mTmpPoint1, mTmpPoint2);
114         if (!mSmallestSize.equals(mTmpPoint1) || !mLargestSize.equals(mTmpPoint2)) {
115             Log.d(TAG, String.format("Available size changed from [%s, %s] to [%s, %s]",
116                     mSmallestSize, mLargestSize, mTmpPoint1, mTmpPoint2));
117             notifyChange();
118         }
119     }
120 
notifyChange()121     private synchronized void notifyChange() {
122         if (mCallback != null) {
123             Consumer<Context> callback = mCallback;
124             mCallback = null;
125             new MainThreadExecutor().execute(() -> callback.accept(mContext));
126         }
127     }
128 
getDefaultDisplay(Context context)129     private Display getDefaultDisplay(Context context) {
130         return context.getSystemService(WindowManager.class).getDefaultDisplay();
131     }
132 
unregister()133     public void unregister() {
134         try {
135             mContext.unregisterReceiver(this);
136             mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this);
137         } catch (Exception e) {
138             Log.e(TAG, "Failed to unregister config monitor", e);
139         }
140     }
141 }
142