1 /**
2  * Copyright (C) 2020 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.power;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.os.RemoteException;
24 import android.os.ServiceManager;
25 import android.util.ArraySet;
26 import android.util.Pair;
27 import android.util.Slog;
28 
29 import com.android.internal.statusbar.IStatusBarService;
30 
31 import java.io.PrintWriter;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.Set;
36 
37 /**
38  * Communicates with System UI to suppress the ambient display.
39  */
40 public class AmbientDisplaySuppressionController {
41     private static final String TAG = "AmbientDisplaySuppressionController";
42 
43     private final Set<Pair<String, Integer>> mSuppressionTokens;
44     private final AmbientDisplaySuppressionChangedCallback mCallback;
45     private IStatusBarService mStatusBarService;
46 
47     /** Interface to get a list of available logical devices. */
48     interface AmbientDisplaySuppressionChangedCallback {
49         /**
50          * Called when the suppression state changes.
51          *
52          * @param isSuppressed Whether ambient is suppressed.
53          */
onSuppressionChanged(boolean isSuppressed)54         void onSuppressionChanged(boolean isSuppressed);
55     }
56 
AmbientDisplaySuppressionController( @onNull AmbientDisplaySuppressionChangedCallback callback)57     AmbientDisplaySuppressionController(
58             @NonNull AmbientDisplaySuppressionChangedCallback callback) {
59         mSuppressionTokens = Collections.synchronizedSet(new ArraySet<>());
60         mCallback = requireNonNull(callback);
61     }
62 
63     /**
64      * Suppresses ambient display.
65      *
66      * @param token A persistible identifier for the ambient display suppression.
67      * @param callingUid The uid of the calling application.
68      * @param suppress If true, suppresses the ambient display. Otherwise, unsuppresses it.
69      */
suppress(@onNull String token, int callingUid, boolean suppress)70     public void suppress(@NonNull String token, int callingUid, boolean suppress) {
71         Pair<String, Integer> suppressionToken = Pair.create(requireNonNull(token), callingUid);
72         final boolean wasSuppressed = isSuppressed();
73 
74         if (suppress) {
75             mSuppressionTokens.add(suppressionToken);
76         } else {
77             mSuppressionTokens.remove(suppressionToken);
78         }
79 
80         final boolean isSuppressed = isSuppressed();
81         if (isSuppressed != wasSuppressed) {
82             mCallback.onSuppressionChanged(isSuppressed);
83         }
84 
85         try {
86             synchronized (mSuppressionTokens) {
87                 getStatusBar().suppressAmbientDisplay(isSuppressed);
88             }
89         } catch (RemoteException e) {
90             Slog.e(TAG, "Failed to suppress ambient display", e);
91         }
92     }
93 
94     /**
95      * Returns the tokens used to suppress ambient display through
96      * {@link #suppress(String, int, boolean)}.
97      *
98      * @param callingUid The uid of the calling application.
99      */
getSuppressionTokens(int callingUid)100     List<String> getSuppressionTokens(int callingUid) {
101         List<String> result = new ArrayList<>();
102         synchronized (mSuppressionTokens) {
103             for (Pair<String, Integer> token : mSuppressionTokens) {
104                 if (token.second == callingUid) {
105                     result.add(token.first);
106                 }
107             }
108         }
109         return result;
110     }
111 
112     /**
113      * Returns whether ambient display is suppressed for the given token.
114      *
115      * @param token A persistible identifier for the ambient display suppression.
116      * @param callingUid The uid of the calling application.
117      */
isSuppressed(@onNull String token, int callingUid)118     public boolean isSuppressed(@NonNull String token, int callingUid) {
119         return mSuppressionTokens.contains(Pair.create(requireNonNull(token), callingUid));
120     }
121 
122     /**
123      * Returns whether ambient display is suppressed.
124      */
isSuppressed()125     public boolean isSuppressed() {
126         return !mSuppressionTokens.isEmpty();
127     }
128 
129     /**
130      * Dumps the state of ambient display suppression and the list of suppression tokens into
131      * {@code pw}.
132      */
dump(PrintWriter pw)133     public void dump(PrintWriter pw) {
134         pw.println("AmbientDisplaySuppressionController:");
135         pw.println(" ambientDisplaySuppressed=" + isSuppressed());
136         pw.println(" mSuppressionTokens=" + mSuppressionTokens);
137     }
138 
getStatusBar()139     private synchronized IStatusBarService getStatusBar() {
140         if (mStatusBarService == null) {
141             mStatusBarService = IStatusBarService.Stub.asInterface(
142                     ServiceManager.getService(Context.STATUS_BAR_SERVICE));
143         }
144         return mStatusBarService;
145     }
146 }
147