1/* 2** 3** Copyright 2013, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18 19package com.android.commands.wm; 20 21import android.content.Context; 22import android.graphics.Point; 23import android.graphics.Rect; 24import android.os.RemoteException; 25import android.os.ServiceManager; 26import android.os.UserHandle; 27import android.util.AndroidException; 28import android.util.DisplayMetrics; 29import android.view.Display; 30import android.view.IWindowManager; 31import com.android.internal.os.BaseCommand; 32 33import java.io.PrintStream; 34import java.util.regex.Matcher; 35import java.util.regex.Pattern; 36 37public class Wm extends BaseCommand { 38 39 private IWindowManager mWm; 40 41 /** 42 * Command-line entry point. 43 * 44 * @param args The command-line arguments 45 */ 46 public static void main(String[] args) { 47 (new Wm()).run(args); 48 } 49 50 @Override 51 public void onShowUsage(PrintStream out) { 52 out.println( 53 "usage: wm [subcommand] [options]\n" + 54 " wm size [reset|WxH|WdpxHdp]\n" + 55 " wm density [reset|DENSITY]\n" + 56 " wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" + 57 " wm scaling [off|auto]\n" + 58 " wm screen-capture [userId] [true|false]\n" + 59 "\n" + 60 "wm size: return or override display size.\n" + 61 " width and height in pixels unless suffixed with 'dp'.\n" + 62 "\n" + 63 "wm density: override display density.\n" + 64 "\n" + 65 "wm overscan: set overscan area for display.\n" + 66 "\n" + 67 "wm scaling: set display scaling mode.\n" + 68 "\n" + 69 "wm screen-capture: enable/disable screen capture.\n" + 70 "\n" + 71 "wm dismiss-keyguard: dismiss the keyguard, prompting the user for auth if " + 72 "necessary.\n" 73 ); 74 } 75 76 @Override 77 public void onRun() throws Exception { 78 mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService( 79 Context.WINDOW_SERVICE)); 80 if (mWm == null) { 81 System.err.println(NO_SYSTEM_ERROR_CODE); 82 throw new AndroidException("Can't connect to window manager; is the system running?"); 83 } 84 85 String op = nextArgRequired(); 86 87 if (op.equals("size")) { 88 runDisplaySize(); 89 } else if (op.equals("density")) { 90 runDisplayDensity(); 91 } else if (op.equals("overscan")) { 92 runDisplayOverscan(); 93 } else if (op.equals("scaling")) { 94 runDisplayScaling(); 95 } else if (op.equals("screen-capture")) { 96 runSetScreenCapture(); 97 } else if (op.equals("dismiss-keyguard")) { 98 runDismissKeyguard(); 99 } else { 100 showError("Error: unknown command '" + op + "'"); 101 return; 102 } 103 } 104 105 private void runSetScreenCapture() throws Exception { 106 String userIdStr = nextArg(); 107 String enableStr = nextArg(); 108 int userId; 109 boolean disable; 110 111 try { 112 userId = Integer.parseInt(userIdStr); 113 } catch (NumberFormatException e) { 114 System.err.println("Error: bad number " + e); 115 return; 116 } 117 118 disable = !Boolean.parseBoolean(enableStr); 119 120 try { 121 mWm.setScreenCaptureDisabled(userId, disable); 122 } catch (RemoteException e) { 123 System.err.println("Error: Can't set screen capture " + e); 124 } 125 } 126 127 private void runDisplaySize() throws Exception { 128 String size = nextArg(); 129 int w, h; 130 if (size == null) { 131 Point initialSize = new Point(); 132 Point baseSize = new Point(); 133 try { 134 mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize); 135 mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize); 136 System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y); 137 if (!initialSize.equals(baseSize)) { 138 System.out.println("Override size: " + baseSize.x + "x" + baseSize.y); 139 } 140 } catch (RemoteException e) { 141 } 142 return; 143 } else if ("reset".equals(size)) { 144 w = h = -1; 145 } else { 146 int div = size.indexOf('x'); 147 if (div <= 0 || div >= (size.length()-1)) { 148 System.err.println("Error: bad size " + size); 149 return; 150 } 151 String wstr = size.substring(0, div); 152 String hstr = size.substring(div+1); 153 try { 154 w = parseDimension(wstr); 155 h = parseDimension(hstr); 156 } catch (NumberFormatException e) { 157 System.err.println("Error: bad number " + e); 158 return; 159 } 160 } 161 162 try { 163 if (w >= 0 && h >= 0) { 164 // TODO(multidisplay): For now Configuration only applies to main screen. 165 mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h); 166 } else { 167 mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY); 168 } 169 } catch (RemoteException e) { 170 } 171 } 172 173 private void runDisplayDensity() throws Exception { 174 String densityStr = nextArg(); 175 int density; 176 if (densityStr == null) { 177 try { 178 int initialDensity = mWm.getInitialDisplayDensity(Display.DEFAULT_DISPLAY); 179 int baseDensity = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY); 180 System.out.println("Physical density: " + initialDensity); 181 if (initialDensity != baseDensity) { 182 System.out.println("Override density: " + baseDensity); 183 } 184 } catch (RemoteException e) { 185 } 186 return; 187 } else if ("reset".equals(densityStr)) { 188 density = -1; 189 } else { 190 try { 191 density = Integer.parseInt(densityStr); 192 } catch (NumberFormatException e) { 193 System.err.println("Error: bad number " + e); 194 return; 195 } 196 if (density < 72) { 197 System.err.println("Error: density must be >= 72"); 198 return; 199 } 200 } 201 202 try { 203 if (density > 0) { 204 // TODO(multidisplay): For now Configuration only applies to main screen. 205 mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density, 206 UserHandle.USER_CURRENT); 207 } else { 208 mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, 209 UserHandle.USER_CURRENT); 210 } 211 } catch (RemoteException e) { 212 } 213 } 214 215 private void runDisplayOverscan() throws Exception { 216 String overscanStr = nextArgRequired(); 217 Rect rect = new Rect(); 218 if ("reset".equals(overscanStr)) { 219 rect.set(0, 0, 0, 0); 220 } else { 221 final Pattern FLATTENED_PATTERN = Pattern.compile( 222 "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)"); 223 Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr); 224 if (!matcher.matches()) { 225 System.err.println("Error: bad rectangle arg: " + overscanStr); 226 return; 227 } 228 rect.left = Integer.parseInt(matcher.group(1)); 229 rect.top = Integer.parseInt(matcher.group(2)); 230 rect.right = Integer.parseInt(matcher.group(3)); 231 rect.bottom = Integer.parseInt(matcher.group(4)); 232 } 233 234 try { 235 mWm.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right, rect.bottom); 236 } catch (RemoteException e) { 237 } 238 } 239 240 private void runDisplayScaling() throws Exception { 241 String scalingStr = nextArgRequired(); 242 if ("auto".equals(scalingStr)) { 243 mWm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 0); 244 } else if ("off".equals(scalingStr)) { 245 mWm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1); 246 } else { 247 System.err.println("Error: scaling must be 'auto' or 'off'"); 248 } 249 } 250 251 private void runDismissKeyguard() throws Exception { 252 mWm.dismissKeyguard(); 253 } 254 255 private int parseDimension(String s) throws NumberFormatException { 256 if (s.endsWith("px")) { 257 return Integer.parseInt(s.substring(0, s.length() - 2)); 258 } 259 if (s.endsWith("dp")) { 260 int density; 261 try { 262 density = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY); 263 } catch (RemoteException e) { 264 density = DisplayMetrics.DENSITY_DEFAULT; 265 } 266 return Integer.parseInt(s.substring(0, s.length() - 2)) * density / 267 DisplayMetrics.DENSITY_DEFAULT; 268 } 269 return Integer.parseInt(s); 270 } 271} 272