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.content.ComponentName; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.os.IBinder; 23 import android.os.Parcel; 24 import android.os.RemoteException; 25 import android.os.ServiceManager; 26 import android.os.SystemProperties; 27 import android.provider.Settings; 28 import android.service.quicksettings.Tile; 29 import android.service.quicksettings.TileService; 30 import android.support.annotation.VisibleForTesting; 31 import android.util.EventLog; 32 import android.util.Log; 33 import android.view.IWindowManager; 34 import android.view.ThreadedRenderer; 35 import android.view.View; 36 import android.view.WindowManagerGlobal; 37 import android.widget.Toast; 38 39 import com.android.internal.app.LocalePicker; 40 import com.android.internal.statusbar.IStatusBarService; 41 import com.android.settingslib.development.DevelopmentSettingsEnabler; 42 import com.android.settingslib.development.SystemPropPoker; 43 44 public abstract class DevelopmentTiles extends TileService { 45 private static final String TAG = "DevelopmentTiles"; 46 isEnabled()47 protected abstract boolean isEnabled(); 48 setIsEnabled(boolean isEnabled)49 protected abstract void setIsEnabled(boolean isEnabled); 50 51 @Override onStartListening()52 public void onStartListening() { 53 super.onStartListening(); 54 refresh(); 55 } 56 refresh()57 public void refresh() { 58 final int state; 59 if (!DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(this)) { 60 // Reset to disabled state if dev option is off. 61 if (isEnabled()) { 62 setIsEnabled(false); 63 SystemPropPoker.getInstance().poke(); 64 } 65 final ComponentName cn = new ComponentName(getPackageName(), getClass().getName()); 66 try { 67 getPackageManager().setComponentEnabledSetting( 68 cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 69 PackageManager.DONT_KILL_APP); 70 final IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( 71 ServiceManager.checkService(Context.STATUS_BAR_SERVICE)); 72 if (statusBarService != null) { 73 EventLog.writeEvent(0x534e4554, "117770924"); // SaftyNet 74 statusBarService.remTile(cn); 75 } 76 } catch (RemoteException e) { 77 Log.e(TAG, "Failed to modify QS tile for component " + 78 cn.toString(), e); 79 } 80 state = Tile.STATE_UNAVAILABLE; 81 } else { 82 state = isEnabled() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; 83 } 84 getQsTile().setState(state); 85 getQsTile().updateTile(); 86 } 87 88 @Override onClick()89 public void onClick() { 90 setIsEnabled(getQsTile().getState() == Tile.STATE_INACTIVE); 91 SystemPropPoker.getInstance().poke(); // Settings app magic 92 refresh(); 93 } 94 95 /** 96 * Tile to control the "Show layout bounds" developer setting 97 */ 98 public static class ShowLayout extends DevelopmentTiles { 99 100 @Override isEnabled()101 protected boolean isEnabled() { 102 return SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false); 103 } 104 105 @Override setIsEnabled(boolean isEnabled)106 protected void setIsEnabled(boolean isEnabled) { 107 SystemProperties.set(View.DEBUG_LAYOUT_PROPERTY, isEnabled ? "true" : "false"); 108 } 109 } 110 111 /** 112 * Tile to control the "GPU profiling" developer setting 113 */ 114 public static class GPUProfiling extends DevelopmentTiles { 115 116 @Override isEnabled()117 protected boolean isEnabled() { 118 final String value = SystemProperties.get(ThreadedRenderer.PROFILE_PROPERTY); 119 return value.equals("visual_bars"); 120 } 121 122 @Override setIsEnabled(boolean isEnabled)123 protected void setIsEnabled(boolean isEnabled) { 124 SystemProperties.set(ThreadedRenderer.PROFILE_PROPERTY, isEnabled ? "visual_bars" : ""); 125 } 126 } 127 128 /** 129 * Tile to control the "Force RTL" developer setting 130 */ 131 public static class ForceRTL extends DevelopmentTiles { 132 133 @Override isEnabled()134 protected boolean isEnabled() { 135 return Settings.Global.getInt( 136 getContentResolver(), Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0; 137 } 138 139 @Override setIsEnabled(boolean isEnabled)140 protected void setIsEnabled(boolean isEnabled) { 141 Settings.Global.putInt( 142 getContentResolver(), Settings.Global.DEVELOPMENT_FORCE_RTL, isEnabled ? 1 : 0); 143 SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, isEnabled ? "1" : "0"); 144 LocalePicker.updateLocales(getResources().getConfiguration().getLocales()); 145 } 146 } 147 148 /** 149 * Tile to control the "Animation speed" developer setting 150 */ 151 public static class AnimationSpeed extends DevelopmentTiles { 152 153 @Override isEnabled()154 protected boolean isEnabled() { 155 IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); 156 try { 157 return wm.getAnimationScale(0) != 1; 158 } catch (RemoteException e) { } 159 return false; 160 } 161 162 @Override setIsEnabled(boolean isEnabled)163 protected void setIsEnabled(boolean isEnabled) { 164 IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); 165 float scale = isEnabled ? 10 : 1; 166 try { 167 wm.setAnimationScale(0, scale); 168 wm.setAnimationScale(1, scale); 169 wm.setAnimationScale(2, scale); 170 } catch (RemoteException e) { } 171 } 172 } 173 174 /** 175 * Tile to toggle Winscope trace which consists of Window and Layer traces. 176 */ 177 public static class WinscopeTrace extends DevelopmentTiles { 178 @VisibleForTesting 179 static final int SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE = 1025; 180 @VisibleForTesting 181 static final int SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE = 1026; 182 private IBinder mSurfaceFlinger; 183 private IWindowManager mWindowManager; 184 private Toast mToast; 185 186 @Override onCreate()187 public void onCreate() { 188 super.onCreate(); 189 mWindowManager = WindowManagerGlobal.getWindowManagerService(); 190 mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger"); 191 Context context = getApplicationContext(); 192 CharSequence text = "Trace files written to /data/misc/wmtrace"; 193 mToast = Toast.makeText(context, text, Toast.LENGTH_LONG); 194 } 195 isWindowTraceEnabled()196 private boolean isWindowTraceEnabled() { 197 try { 198 return mWindowManager.isWindowTraceEnabled(); 199 } catch (RemoteException e) { 200 Log.e(TAG, 201 "Could not get window trace status, defaulting to false." + e.toString()); 202 } 203 return false; 204 } 205 isLayerTraceEnabled()206 private boolean isLayerTraceEnabled() { 207 boolean layerTraceEnabled = false; 208 Parcel reply = null; 209 Parcel data = null; 210 try { 211 if (mSurfaceFlinger != null) { 212 reply = Parcel.obtain(); 213 data = Parcel.obtain(); 214 data.writeInterfaceToken("android.ui.ISurfaceComposer"); 215 mSurfaceFlinger.transact(SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE, 216 data, reply, 0 /* flags */); 217 layerTraceEnabled = reply.readBoolean(); 218 } 219 } catch (RemoteException e) { 220 Log.e(TAG, "Could not get layer trace status, defaulting to false." + e.toString()); 221 } finally { 222 if (data != null) { 223 data.recycle(); 224 reply.recycle(); 225 } 226 } 227 return layerTraceEnabled; 228 } 229 230 @Override isEnabled()231 protected boolean isEnabled() { 232 return isWindowTraceEnabled() || isLayerTraceEnabled(); 233 } 234 setWindowTraceEnabled(boolean isEnabled)235 private void setWindowTraceEnabled(boolean isEnabled) { 236 try { 237 if (isEnabled) { 238 mWindowManager.startWindowTrace(); 239 } else { 240 mWindowManager.stopWindowTrace(); 241 } 242 } catch (RemoteException e) { 243 Log.e(TAG, "Could not set window trace status." + e.toString()); 244 } 245 } 246 setLayerTraceEnabled(boolean isEnabled)247 private void setLayerTraceEnabled(boolean isEnabled) { 248 Parcel data = null; 249 try { 250 if (mSurfaceFlinger != null) { 251 data = Parcel.obtain(); 252 data.writeInterfaceToken("android.ui.ISurfaceComposer"); 253 data.writeInt(isEnabled ? 1 : 0); 254 mSurfaceFlinger.transact(SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE, 255 data, null, 0 /* flags */); 256 } 257 } catch (RemoteException e) { 258 Log.e(TAG, "Could not set layer tracing." + e.toString()); 259 } finally { 260 if (data != null) { 261 data.recycle(); 262 } 263 } 264 } 265 266 @Override setIsEnabled(boolean isEnabled)267 protected void setIsEnabled(boolean isEnabled) { 268 setWindowTraceEnabled(isEnabled); 269 setLayerTraceEnabled(isEnabled); 270 if (!isEnabled) { 271 mToast.show(); 272 } 273 } 274 } 275 } 276