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