1 /*
2  * Copyright (C) 2022 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.systemui.statusbar.policy;
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.pm.PackageManager;
24 import android.os.Handler;
25 import android.safetycenter.SafetyCenterManager;
26 
27 import androidx.annotation.NonNull;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.systemui.dagger.qualifiers.Background;
31 
32 import java.util.ArrayList;
33 import java.util.Objects;
34 
35 import javax.inject.Inject;
36 
37 /**
38  * Controller which calls listeners when a PACKAGE_CHANGED broadcast is sent for the
39  * PermissionController. These broadcasts may be because the PermissionController enabled or
40  * disabled its TileService, and the tile should be added if the component was enabled, or removed
41  * if disabled.
42  */
43 public class SafetyController implements
44         CallbackController<SafetyController.Listener> {
45     private boolean mSafetyCenterEnabled;
46     private final Handler mBgHandler;
47     private final ArrayList<Listener> mListeners = new ArrayList<>();
48     private static final IntentFilter PKG_CHANGE_INTENT_FILTER;
49     private final Context mContext;
50     private final SafetyCenterManager mSafetyCenterManager;
51     private final PackageManager mPackageManager;
52 
53     static {
54         PKG_CHANGE_INTENT_FILTER = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
55         PKG_CHANGE_INTENT_FILTER.addDataScheme("package");
56     }
57 
58     @Inject
SafetyController(Context context, PackageManager pm, SafetyCenterManager scm, @Background Handler bgHandler)59     public SafetyController(Context context, PackageManager pm, SafetyCenterManager scm,
60             @Background Handler bgHandler) {
61         mContext = context;
62         mSafetyCenterManager = scm;
63         mPackageManager = pm;
64         mBgHandler = bgHandler;
65         mSafetyCenterEnabled = mSafetyCenterManager.isSafetyCenterEnabled();
66     }
67 
isSafetyCenterEnabled()68     public boolean isSafetyCenterEnabled() {
69         return mSafetyCenterEnabled;
70     }
71 
72     /**
73      * Adds a listener, registering the broadcast receiver if need be. Immediately calls the
74      * provided listener on the calling thread.
75      */
76     @Override
addCallback(@onNull Listener listener)77     public void addCallback(@NonNull Listener listener) {
78         synchronized (mListeners) {
79             mListeners.add(listener);
80             if (mListeners.size() == 1) {
81                 mContext.registerReceiver(mPermControllerChangeReceiver, PKG_CHANGE_INTENT_FILTER);
82                 mBgHandler.post(() -> {
83                     mSafetyCenterEnabled = mSafetyCenterManager.isSafetyCenterEnabled();
84                     listener.onSafetyCenterEnableChanged(isSafetyCenterEnabled());
85                 });
86             } else {
87                 listener.onSafetyCenterEnableChanged(isSafetyCenterEnabled());
88             }
89         }
90     }
91 
92     @Override
removeCallback(@onNull Listener listener)93     public void removeCallback(@NonNull Listener listener) {
94         synchronized (mListeners) {
95             mListeners.remove(listener);
96             if (mListeners.isEmpty()) {
97                 mContext.unregisterReceiver(mPermControllerChangeReceiver);
98             }
99         }
100     }
101 
handleSafetyCenterEnableChange()102     private void handleSafetyCenterEnableChange() {
103         synchronized (mListeners) {
104             for (int i = 0; i < mListeners.size(); i++) {
105                 mListeners.get(i).onSafetyCenterEnableChanged(mSafetyCenterEnabled);
106             }
107         }
108     }
109 
110     /**
111      * Upon receiving a package changed broadcast for the PermissionController, checks if the
112      * safety center is enabled or disabled, and sends an update on the main thread if the state
113      * changed.
114      */
115     @VisibleForTesting
116     final BroadcastReceiver mPermControllerChangeReceiver = new BroadcastReceiver() {
117         @Override
118         public void onReceive(Context context, Intent intent) {
119             String packageName = intent.getData() != null ? intent.getData().getSchemeSpecificPart()
120                     : null;
121             if (!Objects.equals(packageName,
122                     mPackageManager.getPermissionControllerPackageName())) {
123                 return;
124             }
125 
126             boolean wasSafetyCenterEnabled = mSafetyCenterEnabled;
127             mSafetyCenterEnabled = mSafetyCenterManager.isSafetyCenterEnabled();
128             if (wasSafetyCenterEnabled == mSafetyCenterEnabled) {
129                 return;
130             }
131 
132             mBgHandler.post(() -> handleSafetyCenterEnableChange());
133         }
134     };
135 
136     /**
137      * Listener for safety center enabled changes
138      */
139     public interface Listener {
140         /**
141          * Callback to be notified when the safety center is enabled or disabled
142          * @param isSafetyCenterEnabled If the safety center is enabled
143          */
onSafetyCenterEnableChanged(boolean isSafetyCenterEnabled)144         void onSafetyCenterEnableChanged(boolean isSafetyCenterEnabled);
145     }
146 }
147