• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.settings.development.qstile;
18 
19 import android.app.settings.SettingsEnums;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.hardware.SensorPrivacyManager;
24 import android.app.KeyguardManager;
25 import android.os.IBinder;
26 import android.os.Parcel;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.os.SystemProperties;
30 import android.provider.Settings;
31 import android.service.quicksettings.Tile;
32 import android.service.quicksettings.TileService;
33 import android.sysprop.DisplayProperties;
34 import android.util.Log;
35 import android.view.IWindowManager;
36 import android.view.ThreadedRenderer;
37 import android.view.WindowManagerGlobal;
38 import android.widget.Toast;
39 
40 import androidx.annotation.VisibleForTesting;
41 
42 import com.android.internal.app.LocalePicker;
43 import com.android.internal.statusbar.IStatusBarService;
44 import com.android.settings.overlay.FeatureFactory;
45 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
46 import com.android.settingslib.development.DevelopmentSettingsEnabler;
47 import com.android.settingslib.development.SystemPropPoker;
48 
49 public abstract class DevelopmentTiles extends TileService {
50     private static final String TAG = "DevelopmentTiles";
51 
isEnabled()52     protected abstract boolean isEnabled();
53 
setIsEnabled(boolean isEnabled)54     protected abstract void setIsEnabled(boolean isEnabled);
55 
56     @Override
onStartListening()57     public void onStartListening() {
58         super.onStartListening();
59         refresh();
60     }
61 
refresh()62     public void refresh() {
63         final int state;
64         if (!DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(this)) {
65             // Reset to disabled state if dev option is off.
66             if (isEnabled()) {
67                 setIsEnabled(false);
68                 SystemPropPoker.getInstance().poke();
69             }
70             final ComponentName cn = new ComponentName(getPackageName(), getClass().getName());
71             try {
72                 getPackageManager().setComponentEnabledSetting(
73                         cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
74                         PackageManager.DONT_KILL_APP);
75                 final IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
76                         ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
77                 if (statusBarService != null) {
78                     statusBarService.remTile(cn);
79                 }
80             } catch (RemoteException e) {
81                 Log.e(TAG, "Failed to modify QS tile for component " +
82                         cn.toString(), e);
83             }
84             state = Tile.STATE_UNAVAILABLE;
85         } else {
86             state = isEnabled() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
87         }
88         getQsTile().setState(state);
89         getQsTile().updateTile();
90     }
91 
92     @Override
onClick()93     public void onClick() {
94         setIsEnabled(getQsTile().getState() == Tile.STATE_INACTIVE);
95         SystemPropPoker.getInstance().poke(); // Settings app magic
96         refresh();
97     }
98 
99     /**
100      * Tile to control the "Show layout bounds" developer setting
101      */
102     public static class ShowLayout extends DevelopmentTiles {
103 
104         @Override
isEnabled()105         protected boolean isEnabled() {
106             return DisplayProperties.debug_layout().orElse(false);
107         }
108 
109         @Override
setIsEnabled(boolean isEnabled)110         protected void setIsEnabled(boolean isEnabled) {
111             DisplayProperties.debug_layout(isEnabled);
112         }
113     }
114 
115     /**
116      * Tile to control the "GPU profiling" developer setting
117      */
118     public static class GPUProfiling extends DevelopmentTiles {
119 
120         @Override
isEnabled()121         protected boolean isEnabled() {
122             final String value = SystemProperties.get(ThreadedRenderer.PROFILE_PROPERTY);
123             return value.equals("visual_bars");
124         }
125 
126         @Override
setIsEnabled(boolean isEnabled)127         protected void setIsEnabled(boolean isEnabled) {
128             SystemProperties.set(ThreadedRenderer.PROFILE_PROPERTY, isEnabled ? "visual_bars" : "");
129         }
130     }
131 
132     /**
133      * Tile to control the "Force RTL" developer setting
134      */
135     public static class ForceRTL extends DevelopmentTiles {
136 
137         @Override
isEnabled()138         protected boolean isEnabled() {
139             return Settings.Global.getInt(
140                     getContentResolver(), Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
141         }
142 
143         @Override
setIsEnabled(boolean isEnabled)144         protected void setIsEnabled(boolean isEnabled) {
145             Settings.Global.putInt(
146                     getContentResolver(), Settings.Global.DEVELOPMENT_FORCE_RTL, isEnabled ? 1 : 0);
147             DisplayProperties.debug_force_rtl(isEnabled);
148             LocalePicker.updateLocales(getResources().getConfiguration().getLocales());
149         }
150     }
151 
152     /**
153      * Tile to control the "Animation speed" developer setting
154      */
155     public static class AnimationSpeed extends DevelopmentTiles {
156 
157         @Override
isEnabled()158         protected boolean isEnabled() {
159             IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
160             try {
161                 return wm.getAnimationScale(0) != 1;
162             } catch (RemoteException e) {
163             }
164             return false;
165         }
166 
167         @Override
setIsEnabled(boolean isEnabled)168         protected void setIsEnabled(boolean isEnabled) {
169             IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
170             float scale = isEnabled ? 10 : 1;
171             try {
172                 wm.setAnimationScale(0, scale);
173                 wm.setAnimationScale(1, scale);
174                 wm.setAnimationScale(2, scale);
175             } catch (RemoteException e) {
176             }
177         }
178     }
179 
180     /**
181      * Tile to toggle Winscope trace which consists of Window and Layer traces.
182      */
183     public static class WinscopeTrace extends DevelopmentTiles {
184         @VisibleForTesting
185         static final int SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE = 1025;
186         @VisibleForTesting
187         static final int SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE = 1026;
188         private IBinder mSurfaceFlinger;
189         private IWindowManager mWindowManager;
190         private Toast mToast;
191 
192         @Override
onCreate()193         public void onCreate() {
194             super.onCreate();
195             mWindowManager = WindowManagerGlobal.getWindowManagerService();
196             mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
197             Context context = getApplicationContext();
198             CharSequence text = "Trace files written to /data/misc/wmtrace";
199             mToast = Toast.makeText(context, text, Toast.LENGTH_LONG);
200         }
201 
isWindowTraceEnabled()202         private boolean isWindowTraceEnabled() {
203             try {
204                 return mWindowManager.isWindowTraceEnabled();
205             } catch (RemoteException e) {
206                 Log.e(TAG,
207                         "Could not get window trace status, defaulting to false." + e.toString());
208             }
209             return false;
210         }
211 
isLayerTraceEnabled()212         private boolean isLayerTraceEnabled() {
213             boolean layerTraceEnabled = false;
214             Parcel reply = null;
215             Parcel data = null;
216             try {
217                 if (mSurfaceFlinger != null) {
218                     reply = Parcel.obtain();
219                     data = Parcel.obtain();
220                     data.writeInterfaceToken("android.ui.ISurfaceComposer");
221                     mSurfaceFlinger.transact(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE,
222                             data, reply, 0 /* flags */);
223                     layerTraceEnabled = reply.readBoolean();
224                 }
225             } catch (RemoteException e) {
226                 Log.e(TAG, "Could not get layer trace status, defaulting to false." + e.toString());
227             } finally {
228                 if (data != null) {
229                     data.recycle();
230                     reply.recycle();
231                 }
232             }
233             return layerTraceEnabled;
234         }
235 
236         @Override
isEnabled()237         protected boolean isEnabled() {
238             return isWindowTraceEnabled() || isLayerTraceEnabled();
239         }
240 
setWindowTraceEnabled(boolean isEnabled)241         private void setWindowTraceEnabled(boolean isEnabled) {
242             try {
243                 if (isEnabled) {
244                     mWindowManager.startWindowTrace();
245                 } else {
246                     mWindowManager.stopWindowTrace();
247                 }
248             } catch (RemoteException e) {
249                 Log.e(TAG, "Could not set window trace status." + e.toString());
250             }
251         }
252 
setLayerTraceEnabled(boolean isEnabled)253         private void setLayerTraceEnabled(boolean isEnabled) {
254             Parcel data = null;
255             try {
256                 if (mSurfaceFlinger != null) {
257                     data = Parcel.obtain();
258                     data.writeInterfaceToken("android.ui.ISurfaceComposer");
259                     data.writeInt(isEnabled ? 1 : 0);
260                     mSurfaceFlinger.transact(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE,
261                             data, null, 0 /* flags */);
262                 }
263             } catch (RemoteException e) {
264                 Log.e(TAG, "Could not set layer tracing." + e.toString());
265             } finally {
266                 if (data != null) {
267                     data.recycle();
268                 }
269             }
270         }
271 
272         @Override
setIsEnabled(boolean isEnabled)273         protected void setIsEnabled(boolean isEnabled) {
274             setWindowTraceEnabled(isEnabled);
275             setLayerTraceEnabled(isEnabled);
276             if (!isEnabled) {
277                 mToast.show();
278             }
279         }
280     }
281 
282     /**
283      * Tile to toggle sensors off to control camera, mic, and sensors managed by the SensorManager.
284      */
285     public static class SensorsOff extends DevelopmentTiles {
286         private Context mContext;
287         private SensorPrivacyManager mSensorPrivacyManager;
288         private KeyguardManager mKeyguardManager;
289         private MetricsFeatureProvider mMetricsFeatureProvider;
290         private boolean mIsEnabled;
291 
292         @Override
onCreate()293         public void onCreate() {
294             super.onCreate();
295             mContext = getApplicationContext();
296             mSensorPrivacyManager = (SensorPrivacyManager) mContext.getSystemService(
297                     Context.SENSOR_PRIVACY_SERVICE);
298             mIsEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled();
299             mMetricsFeatureProvider = FeatureFactory.getFactory(
300                     mContext).getMetricsFeatureProvider();
301             mKeyguardManager = (KeyguardManager) mContext.getSystemService(
302                     Context.KEYGUARD_SERVICE);
303         }
304 
305         @Override
isEnabled()306         protected boolean isEnabled() {
307             return mIsEnabled;
308         }
309 
310         @Override
setIsEnabled(boolean isEnabled)311         public void setIsEnabled(boolean isEnabled) {
312             // Don't allow sensors to be reenabled from the lock screen.
313             if (mIsEnabled && mKeyguardManager.isKeyguardLocked()) {
314                 return;
315             }
316             mMetricsFeatureProvider.action(getApplicationContext(), SettingsEnums.QS_SENSOR_PRIVACY,
317                     isEnabled);
318             mIsEnabled = isEnabled;
319             mSensorPrivacyManager.setSensorPrivacy(isEnabled);
320         }
321     }
322 }
323