diff options
Diffstat (limited to 'src/com/android/uiautomator/core/UiDevice.java')
-rw-r--r-- | src/com/android/uiautomator/core/UiDevice.java | 856 |
1 files changed, 856 insertions, 0 deletions
diff --git a/src/com/android/uiautomator/core/UiDevice.java b/src/com/android/uiautomator/core/UiDevice.java new file mode 100644 index 0000000..2a51109 --- /dev/null +++ b/src/com/android/uiautomator/core/UiDevice.java @@ -0,0 +1,856 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.uiautomator.core; + +import android.app.UiAutomation; +import android.app.UiAutomation.AccessibilityEventFilter; +import android.graphics.Point; +import android.os.Build; +import android.os.Environment; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.Display; +import android.view.KeyEvent; +import android.view.Surface; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.TimeoutException; + +/** + * UiDevice provides access to state information about the device. + * You can also use this class to simulate user actions on the device, + * such as pressing the d-pad or pressing the Home and Menu buttons. + * @since API Level 16 + */ +public class UiDevice { + private static final String LOG_TAG = UiDevice.class.getSimpleName(); + + // Sometimes HOME and BACK key presses will generate no events if already on + // home page or there is nothing to go back to, Set low timeouts. + private static final long KEY_PRESS_EVENT_TIMEOUT = 1 * 1000; + + // store for registered UiWatchers + private final HashMap<String, UiWatcher> mWatchers = new HashMap<String, UiWatcher>(); + private final List<String> mWatchersTriggers = new ArrayList<String>(); + + // remember if we're executing in the context of a UiWatcher + private boolean mInWatcherContext = false; + + // provides access the {@link QueryController} and {@link InteractionController} + private InstrumentationUiAutomatorBridge mUiAutomationBridge; + + // reference to self + private static UiDevice sDevice; + + private UiDevice() { + /* hide constructor */ + } + + /** + * @hide + */ + public void initialize(InstrumentationUiAutomatorBridge uiAutomatorBridge) { + mUiAutomationBridge = uiAutomatorBridge; + } + + boolean isInWatcherContext() { + return mInWatcherContext; + } + + /** + * Provides access the {@link QueryController} and {@link InteractionController} + * @return {@link ShellUiAutomatorBridge} + */ + InstrumentationUiAutomatorBridge getAutomatorBridge() { + if (mUiAutomationBridge == null) { + throw new RuntimeException("UiDevice not initialized"); + } + return mUiAutomationBridge; + } + + /** + * Enables or disables layout hierarchy compression. + * + * If compression is enabled, the layout hierarchy derived from the Acessibility + * framework will only contain nodes that are important for uiautomator + * testing. Any unnecessary surrounding layout nodes that make viewing + * and searching the hierarchy inefficient are removed. + * + * @param compressed true to enable compression; else, false to disable + * @since API Level 18 + */ + public void setCompressedLayoutHeirarchy(boolean compressed) { + getAutomatorBridge().setCompressedLayoutHierarchy(compressed); + } + + /** + * Retrieves a singleton instance of UiDevice + * + * @return UiDevice instance + * @since API Level 16 + */ + public static UiDevice getInstance() { + if (sDevice == null) { + sDevice = new UiDevice(); + } + return sDevice; + } + + /** + * Returns the display size in dp (device-independent pixel) + * + * The returned display size is adjusted per screen rotation. Also this will return the actual + * size of the screen, rather than adjusted per system decorations (like status bar). + * + * @return a Point containing the display size in dp + */ + public Point getDisplaySizeDp() { + Tracer.trace(); + Display display = getAutomatorBridge().getDefaultDisplay(); + Point p = new Point(); + display.getRealSize(p); + DisplayMetrics metrics = new DisplayMetrics(); + display.getRealMetrics(metrics); + float dpx = p.x / metrics.density; + float dpy = p.y / metrics.density; + p.x = Math.round(dpx); + p.y = Math.round(dpy); + return p; + } + + /** + * Retrieves the product name of the device. + * + * This method provides information on what type of device the test is running on. This value is + * the same as returned by invoking #adb shell getprop ro.product.name. + * + * @return product name of the device + * @since API Level 17 + */ + public String getProductName() { + Tracer.trace(); + return Build.PRODUCT; + } + + /** + * Retrieves the text from the last UI traversal event received. + * + * You can use this method to read the contents in a WebView container + * because the accessibility framework fires events + * as each text is highlighted. You can write a test to perform + * directional arrow presses to focus on different elements inside a WebView, + * and call this method to get the text from each traversed element. + * If you are testing a view container that can return a reference to a + * Document Object Model (DOM) object, your test should use the view's + * DOM instead. + * + * @return text of the last traversal event, else return an empty string + * @since API Level 16 + */ + public String getLastTraversedText() { + Tracer.trace(); + return getAutomatorBridge().getQueryController().getLastTraversedText(); + } + + /** + * Clears the text from the last UI traversal event. + * See {@link #getLastTraversedText()}. + * @since API Level 16 + */ + public void clearLastTraversedText() { + Tracer.trace(); + getAutomatorBridge().getQueryController().clearLastTraversedText(); + } + + /** + * Simulates a short press on the MENU button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressMenu() { + Tracer.trace(); + waitForIdle(); + return getAutomatorBridge().getInteractionController().sendKeyAndWaitForEvent( + KeyEvent.KEYCODE_MENU, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, + KEY_PRESS_EVENT_TIMEOUT); + } + + /** + * Simulates a short press on the BACK button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressBack() { + Tracer.trace(); + waitForIdle(); + return getAutomatorBridge().getInteractionController().sendKeyAndWaitForEvent( + KeyEvent.KEYCODE_BACK, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, + KEY_PRESS_EVENT_TIMEOUT); + } + + /** + * Simulates a short press on the HOME button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressHome() { + Tracer.trace(); + waitForIdle(); + return getAutomatorBridge().getInteractionController().sendKeyAndWaitForEvent( + KeyEvent.KEYCODE_HOME, 0, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, + KEY_PRESS_EVENT_TIMEOUT); + } + + /** + * Simulates a short press on the SEARCH button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressSearch() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_SEARCH); + } + + /** + * Simulates a short press on the CENTER button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressDPadCenter() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_DPAD_CENTER); + } + + /** + * Simulates a short press on the DOWN button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressDPadDown() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN); + } + + /** + * Simulates a short press on the UP button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressDPadUp() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_DPAD_UP); + } + + /** + * Simulates a short press on the LEFT button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressDPadLeft() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_DPAD_LEFT); + } + + /** + * Simulates a short press on the RIGHT button. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressDPadRight() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT); + } + + /** + * Simulates a short press on the DELETE key. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressDelete() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_DEL); + } + + /** + * Simulates a short press on the ENTER key. + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressEnter() { + Tracer.trace(); + return pressKeyCode(KeyEvent.KEYCODE_ENTER); + } + + /** + * Simulates a short press using a key code. + * + * See {@link KeyEvent} + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressKeyCode(int keyCode) { + Tracer.trace(keyCode); + waitForIdle(); + return getAutomatorBridge().getInteractionController().sendKey(keyCode, 0); + } + + /** + * Simulates a short press using a key code. + * + * See {@link KeyEvent}. + * @param keyCode the key code of the event. + * @param metaState an integer in which each bit set to 1 represents a pressed meta key + * @return true if successful, else return false + * @since API Level 16 + */ + public boolean pressKeyCode(int keyCode, int metaState) { + Tracer.trace(keyCode, metaState); + waitForIdle(); + return getAutomatorBridge().getInteractionController().sendKey(keyCode, metaState); + } + + /** + * Simulates a short press on the Recent Apps button. + * + * @return true if successful, else return false + * @throws RemoteException + * @since API Level 16 + */ + public boolean pressRecentApps() throws RemoteException { + Tracer.trace(); + waitForIdle(); + return getAutomatorBridge().getInteractionController().toggleRecentApps(); + } + + /** + * Opens the notification shade. + * + * @return true if successful, else return false + * @since API Level 18 + */ + public boolean openNotification() { + Tracer.trace(); + waitForIdle(); + return getAutomatorBridge().getInteractionController().openNotification(); + } + + /** + * Opens the Quick Settings shade. + * + * @return true if successful, else return false + * @since API Level 18 + */ + public boolean openQuickSettings() { + Tracer.trace(); + waitForIdle(); + return getAutomatorBridge().getInteractionController().openQuickSettings(); + } + + /** + * Gets the width of the display, in pixels. The width and height details + * are reported based on the current orientation of the display. + * @return width in pixels or zero on failure + * @since API Level 16 + */ + public int getDisplayWidth() { + Tracer.trace(); + Display display = getAutomatorBridge().getDefaultDisplay(); + Point p = new Point(); + display.getSize(p); + return p.x; + } + + /** + * Gets the height of the display, in pixels. The size is adjusted based + * on the current orientation of the display. + * @return height in pixels or zero on failure + * @since API Level 16 + */ + public int getDisplayHeight() { + Tracer.trace(); + Display display = getAutomatorBridge().getDefaultDisplay(); + Point p = new Point(); + display.getSize(p); + return p.y; + } + + /** + * Perform a click at arbitrary coordinates specified by the user + * + * @param x coordinate + * @param y coordinate + * @return true if the click succeeded else false + * @since API Level 16 + */ + public boolean click(int x, int y) { + Tracer.trace(x, y); + if (x >= getDisplayWidth() || y >= getDisplayHeight()) { + return (false); + } + return getAutomatorBridge().getInteractionController().clickNoSync(x, y); + } + + /** + * Performs a swipe from one coordinate to another using the number of steps + * to determine smoothness and speed. Each step execution is throttled to 5ms + * per step. So for a 100 steps, the swipe will take about 1/2 second to complete. + * + * @param startX + * @param startY + * @param endX + * @param endY + * @param steps is the number of move steps sent to the system + * @return false if the operation fails or the coordinates are invalid + * @since API Level 16 + */ + public boolean swipe(int startX, int startY, int endX, int endY, int steps) { + Tracer.trace(startX, startY, endX, endY, steps); + return getAutomatorBridge().getInteractionController() + .swipe(startX, startY, endX, endY, steps); + } + + /** + * Performs a swipe from one coordinate to another coordinate. You can control + * the smoothness and speed of the swipe by specifying the number of steps. + * Each step execution is throttled to 5 milliseconds per step, so for a 100 + * steps, the swipe will take around 0.5 seconds to complete. + * + * @param startX X-axis value for the starting coordinate + * @param startY Y-axis value for the starting coordinate + * @param endX X-axis value for the ending coordinate + * @param endY Y-axis value for the ending coordinate + * @param steps is the number of steps for the swipe action + * @return true if swipe is performed, false if the operation fails + * or the coordinates are invalid + * @since API Level 18 + */ + public boolean drag(int startX, int startY, int endX, int endY, int steps) { + Tracer.trace(startX, startY, endX, endY, steps); + return getAutomatorBridge().getInteractionController() + .swipe(startX, startY, endX, endY, steps, true); + } + + /** + * Performs a swipe between points in the Point array. Each step execution is throttled + * to 5ms per step. So for a 100 steps, the swipe will take about 1/2 second to complete + * + * @param segments is Point array containing at least one Point object + * @param segmentSteps steps to inject between two Points + * @return true on success + * @since API Level 16 + */ + public boolean swipe(Point[] segments, int segmentSteps) { + Tracer.trace(segments, segmentSteps); + return getAutomatorBridge().getInteractionController().swipe(segments, segmentSteps); + } + + /** + * Waits for the current application to idle. + * Default wait timeout is 10 seconds + * @since API Level 16 + */ + public void waitForIdle() { + Tracer.trace(); + waitForIdle(Configurator.getInstance().getWaitForIdleTimeout()); + } + + /** + * Waits for the current application to idle. + * @param timeout in milliseconds + * @since API Level 16 + */ + public void waitForIdle(long timeout) { + Tracer.trace(timeout); + getAutomatorBridge().waitForIdle(timeout); + } + + /** + * Retrieves the last activity to report accessibility events. + * @deprecated The results returned should be considered unreliable + * @return String name of activity + * @since API Level 16 + */ + @Deprecated + public String getCurrentActivityName() { + Tracer.trace(); + return getAutomatorBridge().getQueryController().getCurrentActivityName(); + } + + /** + * Retrieves the name of the last package to report accessibility events. + * @return String name of package + * @since API Level 16 + */ + public String getCurrentPackageName() { + Tracer.trace(); + return getAutomatorBridge().getQueryController().getCurrentPackageName(); + } + + /** + * Registers a {@link UiWatcher} to run automatically when the testing framework is unable to + * find a match using a {@link UiSelector}. See {@link #runWatchers()} + * + * @param name to register the UiWatcher + * @param watcher {@link UiWatcher} + * @since API Level 16 + */ + public void registerWatcher(String name, UiWatcher watcher) { + Tracer.trace(name, watcher); + if (mInWatcherContext) { + throw new IllegalStateException("Cannot register new watcher from within another"); + } + mWatchers.put(name, watcher); + } + + /** + * Removes a previously registered {@link UiWatcher}. + * + * See {@link #registerWatcher(String, UiWatcher)} + * @param name used to register the UiWatcher + * @since API Level 16 + */ + public void removeWatcher(String name) { + Tracer.trace(name); + if (mInWatcherContext) { + throw new IllegalStateException("Cannot remove a watcher from within another"); + } + mWatchers.remove(name); + } + + /** + * This method forces all registered watchers to run. + * See {@link #registerWatcher(String, UiWatcher)} + * @since API Level 16 + */ + public void runWatchers() { + Tracer.trace(); + if (mInWatcherContext) { + return; + } + + for (String watcherName : mWatchers.keySet()) { + UiWatcher watcher = mWatchers.get(watcherName); + if (watcher != null) { + try { + mInWatcherContext = true; + if (watcher.checkForCondition()) { + setWatcherTriggered(watcherName); + } + } catch (Exception e) { + Log.e(LOG_TAG, "Exceuting watcher: " + watcherName, e); + } finally { + mInWatcherContext = false; + } + } + } + } + + /** + * Resets a {@link UiWatcher} that has been triggered. + * If a UiWatcher runs and its {@link UiWatcher#checkForCondition()} call + * returned <code>true</code>, then the UiWatcher is considered triggered. + * See {@link #registerWatcher(String, UiWatcher)} + * @since API Level 16 + */ + public void resetWatcherTriggers() { + Tracer.trace(); + mWatchersTriggers.clear(); + } + + /** + * Checks if a specific registered {@link UiWatcher} has triggered. + * See {@link #registerWatcher(String, UiWatcher)}. If a UiWatcher runs and its + * {@link UiWatcher#checkForCondition()} call returned <code>true</code>, then + * the UiWatcher is considered triggered. This is helpful if a watcher is detecting errors + * from ANR or crash dialogs and the test needs to know if a UiWatcher has been triggered. + * + * @param watcherName + * @return true if triggered else false + * @since API Level 16 + */ + public boolean hasWatcherTriggered(String watcherName) { + Tracer.trace(watcherName); + return mWatchersTriggers.contains(watcherName); + } + + /** + * Checks if any registered {@link UiWatcher} have triggered. + * + * See {@link #registerWatcher(String, UiWatcher)} + * See {@link #hasWatcherTriggered(String)} + * @since API Level 16 + */ + public boolean hasAnyWatcherTriggered() { + Tracer.trace(); + return mWatchersTriggers.size() > 0; + } + + /** + * Used internally by this class to set a {@link UiWatcher} state as triggered. + * @param watcherName + */ + private void setWatcherTriggered(String watcherName) { + Tracer.trace(watcherName); + if (!hasWatcherTriggered(watcherName)) { + mWatchersTriggers.add(watcherName); + } + } + + /** + * Check if the device is in its natural orientation. This is determined by checking if the + * orientation is at 0 or 180 degrees. + * @return true if it is in natural orientation + * @since API Level 17 + */ + public boolean isNaturalOrientation() { + Tracer.trace(); + waitForIdle(); + int ret = getAutomatorBridge().getRotation(); + return ret == UiAutomation.ROTATION_FREEZE_0 || + ret == UiAutomation.ROTATION_FREEZE_180; + } + + /** + * Returns the current rotation of the display, as defined in {@link Surface} + * @since API Level 17 + */ + public int getDisplayRotation() { + Tracer.trace(); + waitForIdle(); + return getAutomatorBridge().getRotation(); + } + + /** + * Disables the sensors and freezes the device rotation at its + * current rotation state. + * @throws RemoteException + * @since API Level 16 + */ + public void freezeRotation() throws RemoteException { + Tracer.trace(); + getAutomatorBridge().getInteractionController().freezeRotation(); + } + + /** + * Re-enables the sensors and un-freezes the device rotation allowing its contents + * to rotate with the device physical rotation. During a test execution, it is best to + * keep the device frozen in a specific orientation until the test case execution has completed. + * @throws RemoteException + */ + public void unfreezeRotation() throws RemoteException { + Tracer.trace(); + getAutomatorBridge().getInteractionController().unfreezeRotation(); + } + + /** + * Simulates orienting the device to the left and also freezes rotation + * by disabling the sensors. + * + * If you want to un-freeze the rotation and re-enable the sensors + * see {@link #unfreezeRotation()}. + * @throws RemoteException + * @since API Level 17 + */ + public void setOrientationLeft() throws RemoteException { + Tracer.trace(); + getAutomatorBridge().getInteractionController().setRotationLeft(); + waitForIdle(); // we don't need to check for idle on entry for this. We'll sync on exit + } + + /** + * Simulates orienting the device to the right and also freezes rotation + * by disabling the sensors. + * + * If you want to un-freeze the rotation and re-enable the sensors + * see {@link #unfreezeRotation()}. + * @throws RemoteException + * @since API Level 17 + */ + public void setOrientationRight() throws RemoteException { + Tracer.trace(); + getAutomatorBridge().getInteractionController().setRotationRight(); + waitForIdle(); // we don't need to check for idle on entry for this. We'll sync on exit + } + + /** + * Simulates orienting the device into its natural orientation and also freezes rotation + * by disabling the sensors. + * + * If you want to un-freeze the rotation and re-enable the sensors + * see {@link #unfreezeRotation()}. + * @throws RemoteException + * @since API Level 17 + */ + public void setOrientationNatural() throws RemoteException { + Tracer.trace(); + getAutomatorBridge().getInteractionController().setRotationNatural(); + waitForIdle(); // we don't need to check for idle on entry for this. We'll sync on exit + } + + /** + * This method simulates pressing the power button if the screen is OFF else + * it does nothing if the screen is already ON. + * + * If the screen was OFF and it just got turned ON, this method will insert a 500ms delay + * to allow the device time to wake up and accept input. + * @throws RemoteException + * @since API Level 16 + */ + public void wakeUp() throws RemoteException { + Tracer.trace(); + if(getAutomatorBridge().getInteractionController().wakeDevice()) { + // sync delay to allow the window manager to start accepting input + // after the device is awakened. + SystemClock.sleep(500); + } + } + + /** + * Checks the power manager if the screen is ON. + * + * @return true if the screen is ON else false + * @throws RemoteException + * @since API Level 16 + */ + public boolean isScreenOn() throws RemoteException { + Tracer.trace(); + return getAutomatorBridge().getInteractionController().isScreenOn(); + } + + /** + * This method simply presses the power button if the screen is ON else + * it does nothing if the screen is already OFF. + * + * @throws RemoteException + * @since API Level 16 + */ + public void sleep() throws RemoteException { + Tracer.trace(); + getAutomatorBridge().getInteractionController().sleepDevice(); + } + + /** + * Helper method used for debugging to dump the current window's layout hierarchy. + * Relative file paths are stored the application's internal private storage location. + * + * @param fileName + * @since API Level 16 + */ + public void dumpWindowHierarchy(String fileName) { + Tracer.trace(fileName); + AccessibilityNodeInfo root = + getAutomatorBridge().getQueryController().getAccessibilityRootNode(); + if(root != null) { + Display display = getAutomatorBridge().getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + File dumpFile = new File(fileName); + if (!dumpFile.isAbsolute()) { + dumpFile = getAutomatorBridge().getContext().getFileStreamPath(fileName); + } + AccessibilityNodeInfoDumper.dumpWindowToFile(root, dumpFile, display.getRotation(), + size.x, size.y); + Log.d(LOG_TAG, String.format("Saved window hierarchy to %s", + dumpFile.getAbsolutePath())); + } + } + + /** + * Waits for a window content update event to occur. + * + * If a package name for the window is specified, but the current window + * does not have the same package name, the function returns immediately. + * + * @param packageName the specified window package name (can be <code>null</code>). + * If <code>null</code>, a window update from any front-end window will end the wait + * @param timeout the timeout for the wait + * + * @return true if a window update occurred, false if timeout has elapsed or if the current + * window does not have the specified package name + * @since API Level 16 + */ + public boolean waitForWindowUpdate(final String packageName, long timeout) { + Tracer.trace(packageName, timeout); + if (packageName != null) { + if (!packageName.equals(getCurrentPackageName())) { + return false; + } + } + Runnable emptyRunnable = new Runnable() { + @Override + public void run() { + } + }; + AccessibilityEventFilter checkWindowUpdate = new AccessibilityEventFilter() { + @Override + public boolean accept(AccessibilityEvent t) { + if (t.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) { + return packageName == null || packageName.equals(t.getPackageName()); + } + return false; + } + }; + try { + getAutomatorBridge().executeCommandAndWaitForAccessibilityEvent( + emptyRunnable, checkWindowUpdate, timeout); + } catch (TimeoutException e) { + return false; + } catch (Exception e) { + Log.e(LOG_TAG, "waitForWindowUpdate: general exception from bridge", e); + return false; + } + return true; + } + + /** + * Take a screenshot of current window and store it as PNG + * + * Default scale of 1.0f (original size) and 90% quality is used + * The screenshot is adjusted per screen rotation + * + * @param storePath where the PNG should be written to + * @return true if screen shot is created successfully, false otherwise + * @since API Level 17 + */ + public boolean takeScreenshot(File storePath) { + Tracer.trace(storePath); + return takeScreenshot(storePath, 1.0f, 90); + } + + /** + * Take a screenshot of current window and store it as PNG + * + * The screenshot is adjusted per screen rotation + * + * @param storePath where the PNG should be written to + * @param scale scale the screenshot down if needed; 1.0f for original size + * @param quality quality of the PNG compression; range: 0-100 + * @return true if screen shot is created successfully, false otherwise + * @since API Level 17 + */ + public boolean takeScreenshot(File storePath, float scale, int quality) { + Tracer.trace(storePath, scale, quality); + return getAutomatorBridge().takeScreenshot(storePath, quality); + } +} |