• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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 
17 package com.android.server.wm;
18 
19 import static android.os.PowerManager.THERMAL_STATUS_CRITICAL;
20 import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED;
21 
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.database.ContentObserver;
27 import android.net.ConnectivityManager;
28 import android.os.PowerManager;
29 import android.os.RemoteCallbackList;
30 import android.os.RemoteException;
31 import android.provider.Settings;
32 import android.view.ICrossWindowBlurEnabledListener;
33 import android.view.TunnelModeEnabledListener;
34 
35 /**
36  * Keeps track of the different factors that determine whether cross-window blur is enabled
37  * or disabled. Also keeps a list of all interested listeners and notifies them when the
38  * blur enabled state changes.
39  */
40 final class BlurController {
41     private final Context mContext;
42     private final RemoteCallbackList<ICrossWindowBlurEnabledListener>
43             mBlurEnabledListeners = new RemoteCallbackList<>();
44     // We don't use the WM global lock, because the BlurController is not involved in window
45     // drawing and only receives binder calls that don't need synchronization with the rest of WM
46     private final Object mLock = new Object();
47     private volatile boolean mBlurEnabled;
48     private boolean mInPowerSaveMode;
49     private boolean mCriticalThermalStatus;
50     private boolean mBlurDisabledSetting;
51     private boolean mTunnelModeEnabled = false;
52 
53     private TunnelModeEnabledListener mTunnelModeListener =
54             new TunnelModeEnabledListener(Runnable::run) {
55         @Override
56         public void onTunnelModeEnabledChanged(boolean tunnelModeEnabled) {
57             mTunnelModeEnabled = tunnelModeEnabled;
58             updateBlurEnabled();
59         }
60     };
61 
BlurController(Context context, PowerManager powerManager)62     BlurController(Context context, PowerManager powerManager) {
63         mContext = context;
64 
65         IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
66         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
67         context.registerReceiverForAllUsers(new BroadcastReceiver() {
68             @Override
69             public void onReceive(Context context, Intent intent) {
70                 if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
71                     // onReceive always gets called on the same thread, so there is no
72                     // multi-threaded execution here. Thus, we don't have to hold mLock here.
73                     mInPowerSaveMode = powerManager.isPowerSaveMode();
74                     updateBlurEnabled();
75                 }
76             }
77         }, filter, null, null);
78         mInPowerSaveMode = powerManager.isPowerSaveMode();
79 
80         context.getContentResolver().registerContentObserver(
81                 Settings.Global.getUriFor(Settings.Global.DISABLE_WINDOW_BLURS), false,
82                 new ContentObserver(null) {
83                     @Override
84                     public void onChange(boolean selfChange) {
85                         super.onChange(selfChange);
86                         // onChange always gets called on the same thread, so there is no
87                         // multi-threaded execution here. Thus, we don't have to hold mLock here.
88                         mBlurDisabledSetting = getBlurDisabledSetting();
89                         updateBlurEnabled();
90                     }
91                 });
92         mBlurDisabledSetting = getBlurDisabledSetting();
93 
94         powerManager.addThermalStatusListener((status) -> {
95             mCriticalThermalStatus = status >= THERMAL_STATUS_CRITICAL;
96             updateBlurEnabled();
97         });
98         mCriticalThermalStatus = powerManager.getCurrentThermalStatus() >= THERMAL_STATUS_CRITICAL;
99 
100         TunnelModeEnabledListener.register(mTunnelModeListener);
101 
102         updateBlurEnabled();
103     }
104 
registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener)105     boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
106         if (listener == null) return false;
107         mBlurEnabledListeners.register(listener);
108         return getBlurEnabled();
109     }
110 
unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener)111     void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) {
112         if (listener == null) return;
113         mBlurEnabledListeners.unregister(listener);
114     }
115 
getBlurEnabled()116     boolean getBlurEnabled() {
117         return mBlurEnabled;
118     }
119 
updateBlurEnabled()120     private void updateBlurEnabled() {
121         synchronized (mLock) {
122             final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurDisabledSetting
123                     && !mInPowerSaveMode && !mTunnelModeEnabled && !mCriticalThermalStatus;
124             if (mBlurEnabled == newEnabled) {
125                 return;
126             }
127             mBlurEnabled = newEnabled;
128             notifyBlurEnabledChangedLocked(newEnabled);
129         }
130     }
131 
notifyBlurEnabledChangedLocked(boolean enabled)132     private void notifyBlurEnabledChangedLocked(boolean enabled) {
133         int i = mBlurEnabledListeners.beginBroadcast();
134         while (i > 0) {
135             i--;
136             ICrossWindowBlurEnabledListener listener =
137                     mBlurEnabledListeners.getBroadcastItem(i);
138             try {
139                 listener.onCrossWindowBlurEnabledChanged(enabled);
140             } catch (RemoteException e) {
141             }
142         }
143         mBlurEnabledListeners.finishBroadcast();
144     }
145 
getBlurDisabledSetting()146     private boolean getBlurDisabledSetting() {
147         return Settings.Global.getInt(mContext.getContentResolver(),
148                 Settings.Global.DISABLE_WINDOW_BLURS, 0) == 1;
149     }
150 }
151