blob: e56268d4c6aaa787747b32c2810a6364bfc1fcb3 [file] [log] [blame]
Ady Abraham678e1872019-11-20 11:13:30 -08001/*
2 * Copyright 2019 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
17package com.android.settings.development;
18
19import android.content.Context;
20import android.os.IBinder;
21import android.os.Parcel;
22import android.os.RemoteException;
23import android.os.ServiceManager;
24
25import androidx.annotation.VisibleForTesting;
26import androidx.preference.Preference;
27import androidx.preference.SwitchPreference;
28
29import com.android.settings.core.PreferenceControllerMixin;
30import com.android.settingslib.development.DeveloperOptionsPreferenceController;
31
32/**
33 * Controller class for controlling the refresh rate overlay on SurfaceFlinger
34 */
35public class ShowRefreshRatePreferenceController extends DeveloperOptionsPreferenceController
36 implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
37
38 private static final String SHOW_REFRESH_RATE_KEY = "show_refresh_rate";
39
40 private static final int SETTING_VALUE_QUERY = 2;
41 private static final int SETTING_VALUE_ON = 1;
42 private static final int SETTING_VALUE_OFF = 0;
43
44 @VisibleForTesting
45 static final String SURFACE_FLINGER_SERVICE_KEY = "SurfaceFlinger";
46 @VisibleForTesting
47 static final int SURFACE_FLINGER_CODE = 1034;
48
49 private static final String SURFACE_COMPOSER_INTERFACE_KEY = "android.ui.ISurfaceComposer";
50
51 private final IBinder mSurfaceFlinger;
52
53 public ShowRefreshRatePreferenceController(Context context) {
54 super(context);
55 mSurfaceFlinger = ServiceManager.getService(SURFACE_FLINGER_SERVICE_KEY);
56 }
57
58 @Override
59 public String getPreferenceKey() {
60 return SHOW_REFRESH_RATE_KEY;
61 }
62
63 @Override
64 public boolean onPreferenceChange(Preference preference, Object newValue) {
65 final boolean isEnabled = (Boolean) newValue;
66 writeShowRefreshRateSetting(isEnabled);
67 return true;
68 }
69
70 @Override
71 public void updateState(Preference preference) {
72 updateShowRefreshRateSetting();
73 }
74
75 @Override
76 protected void onDeveloperOptionsSwitchDisabled() {
77 super.onDeveloperOptionsSwitchDisabled();
78 final SwitchPreference preference = (SwitchPreference) mPreference;
79 if (preference.isChecked()) {
80 // Writing false to the preference when the setting is already off will have a
81 // side effect of turning on the preference that we wish to avoid
82 writeShowRefreshRateSetting(false);
83 preference.setChecked(false);
84 }
85 }
86
87 @VisibleForTesting
88 void updateShowRefreshRateSetting() {
89 // magic communication with surface flinger.
90 try {
91 if (mSurfaceFlinger != null) {
92 final Parcel data = Parcel.obtain();
93 final Parcel reply = Parcel.obtain();
94 data.writeInterfaceToken(SURFACE_COMPOSER_INTERFACE_KEY);
95 data.writeInt(SETTING_VALUE_QUERY);
96 mSurfaceFlinger.transact(SURFACE_FLINGER_CODE, data, reply, 0 /* flags */);
97 final boolean enabled = reply.readBoolean();
98 ((SwitchPreference) mPreference).setChecked(enabled);
99 reply.recycle();
100 data.recycle();
101 }
102 } catch (RemoteException ex) {
103 // intentional no-op
104 }
105 }
106
107 @VisibleForTesting
108 void writeShowRefreshRateSetting(boolean isEnabled) {
109 try {
110 if (mSurfaceFlinger != null) {
111 final Parcel data = Parcel.obtain();
112 data.writeInterfaceToken(SURFACE_COMPOSER_INTERFACE_KEY);
113 final int showRefreshRate = isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF;
114 data.writeInt(showRefreshRate);
115 mSurfaceFlinger.transact(SURFACE_FLINGER_CODE, data,
116 null /* reply */, 0 /* flags */);
117 data.recycle();
118 }
119 } catch (RemoteException ex) {
120 // intentional no-op
121 }
122 updateShowRefreshRateSetting();
123 }
124}