diff options
30 files changed, 4134 insertions, 2581 deletions
diff --git a/api/current.xml b/api/current.xml index ff4942e..b0cb834 100644 --- a/api/current.xml +++ b/api/current.xml @@ -245569,7 +245569,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="t" type="T"> +<parameter name="arg0" type="T"> </parameter> </method> </interface> diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index 37c8ad0..b5fddfa 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -389,11 +389,13 @@ public final class Bmgr { if (err == 0) { observer.waitForCompletion(); sets = observer.sets; - for (RestoreSet s : sets) { - if (s.token == token) { - System.out.println("Scheduling restore: " + s.name); - didRestore = (mRestore.restoreAll(token, observer) == 0); - break; + if (sets != null) { + for (RestoreSet s : sets) { + if (s.token == token) { + System.out.println("Scheduling restore: " + s.name); + didRestore = (mRestore.restoreAll(token, observer) == 0); + break; + } } } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ab97569..a9f0780 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6298,7 +6298,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; - if (ai != null && ai.mHardwareAccelerated) { + if (p != null && ai != null && ai.mHardwareAccelerated) { // fast-track for GL-enabled applications; just invalidate the whole hierarchy // with a null dirty rect, which tells the ViewRoot to redraw everything p.invalidateChild(this, null); diff --git a/docs/html/guide/developing/tools/MonkeyDevice.jd b/docs/html/guide/developing/tools/MonkeyDevice.jd new file mode 100644 index 0000000..34bbba9 --- /dev/null +++ b/docs/html/guide/developing/tools/MonkeyDevice.jd @@ -0,0 +1,1353 @@ +page.title=MonkeyDevice +@jd:body +<style> + h4.jd-details-title {background-color: #DEE8F1;} +</style> +<p> + A monkeyrunner class that represents a device or emulator accessible by the workstation running +<code><a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a></code>. +</p> +<p> + This class is used to control an Android device or emulator. The methods send UI events, + retrieve information, install and remove applications, and run applications. +</p> +<p> + You normally do not have to create an instance of <code>MonkeyDevice</code>. Instead, you + use +<code><a href="{@docRoot}guide/developing/tools/MonkeyRunner.html#waitForConnection"> +MonkeyRunner.waitForConnection()</a></code> to create a new object from a connection to a device or +emulator. For example, instead of +using:</p> +<pre> +newdevice = MonkeyDevice() +</pre> +<p> + you would use: +</p> +<pre> +newdevice = MonkeyRunner.waitForConnection() +</pre> +<h2>Summary</h2> + <table id="constants" class="jd-sumtable" style="background-color: white;"> + <tr> + <th colspan="12" style="background-color: #E2E2E2">Constants</th> + </tr> + <tr class="api" style="background-color: white;"> + <td class="jd-typecol"><em>string</em></td> + <td class="jd-linkcol"><a href="#ACTION_DOWN">DOWN</a></td> + <td class="jd-descrcol" width="100%"> + Use this with the <code>type</code> argument of + <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a> + </code> + to send a DOWN event. + </td> + </tr> + <tr class="api" style="background-color: white;"> + <td class="jd-typecol"><em>string</em></td> + <td class="jd-linkcol"><a href="#ACTION_UP">UP</a></td> + <td class="jd-descrcol" width="100%"> + Use this with the <code>type</code> argument of + <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a> + </code> + to send an UP event. + </td> + </tr> + <tr class="api" style="background-color: white;"> + <td class="jd-typecol"><em>string</em></td> + <td class="jd-linkcol"><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></td> + <td class="jd-descrcol" width="100%"> + Use this with the <code>type</code> argument of + <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a> + </code> + to send a DOWN event immediately followed by an UP event. + </td> + </tr> + </table> +<table id="pubmethods" class="jd-sumtable"> + <tr> + <th colspan="12" style="background-color: #E2E2E2">Methods</th> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#broadcastIntent">broadcastIntent</a> + </span> + (<em>string</em> uri, + <em>string</em> action, + <em>string</em> data, + <em>string</em> mimetype, + <em>iterable</em> categories + <em>dictionary</em> extras, + <em>component</em> component, + <em>iterable</em> flags) + </nobr> + <div class="jd-descrdiv"> + Broadcasts an Intent to this device, as if the Intent were coming from an + application. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#drag">drag</a> + </span> + (<em>tuple</em> start, + <em>tuple</em> end, + <em>float</em> duration, + <em>integer</em> steps) + </nobr> + <div class="jd-descrdiv"> + Simulates a drag gesture (touch, hold, and move) on this device's screen. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>object</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#getProperty">getProperty</a> + </span> + (<em>string</em> key) + </nobr> + <div class="jd-descrdiv"> + Given the name of a system environment variable, returns its value for this device. + The available variable names are listed in the <a href="#getProperty"> + detailed description</a> of this method. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>object</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#getSystemProperty">getSystemProperty</a> + </span> + (<em>string</em> key) + </nobr> + <div class="jd-descrdiv"> +. The API equivalent of <code>adb shell getprop <key>. This is provided for use + by platform developers. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#installPackage">installPackage</a> + </span> + (<em>string</em> path) + </nobr> + <div class="jd-descrdiv"> + Installs the Android application or test package contained in packageFile onto this + device. If the application or test package is already installed, it is replaced. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>dictionary</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#instrument">instrument</a> + </span> + (<em>string</em> className, + <em>dictionary</em> args) + </nobr> + <div class="jd-descrdiv"> + Runs the specified component under Android instrumentation, and returns the results + in a dictionary whose exact format is dictated by the component being run. The + component must already be present on this device. + </div> + </td> + </tr> + <tr class="api"> + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#press">press</a> + </span> + (<em>string</em> name, + <em>dictionary</em> type) + </nobr> + <div class="jd-descrdiv"> + Sends the key event specified by type to the key specified by + keycode. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#reboot">reboot</a> + </span> + (<em>string</em> into) + </nobr> + <div class="jd-descrdiv"> + Reboots this device into the bootloader specified by bootloadType. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#removePackage">removePackage</a> + </span> + (<em>string</em> package) + </nobr> + <div class="jd-descrdiv"> + Deletes the specified package from this device, including its data and cache. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>object</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#shell">shell</a> + </span> + (<em>string</em> cmd) + </nobr> + <div class="jd-descrdiv"> + Executes an <code>adb</code> shell command and returns the result, if any. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#startActivity">startActivity</a> + </span> + (<em>string</em> uri, + <em>string</em> action, + <em>string</em> data, + <em>string</em> mimetype, + <em>iterable</em> categories + <em>dictionary</em> extras, + <em>component</em> component, + <em>flags</em>) + </nobr> + <div class="jd-descrdiv"> + Starts an Activity on this device by sending an Intent constructed from the + supplied arguments. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyImage.html"> + MonkeyImage + </a> + </code> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#takeSnapshot">takeSnapshot</a>() + </span> + </nobr> + <div class="jd-descrdiv"> + Captures the entire screen buffer of this device, yielding a + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyImage.html"> + MonkeyImage + </a> + </code> object containing a screen capture of the current display. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#touch">touch</a> + </span> + (<em>integer</em> x, + <em>integer</em> y, + <em>integer</em> type) + </nobr> + <div class="jd-descrdiv"> + Sends a touch event specified by type to the screen location specified + by x and y. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#touch">type</a> + </span> + (<em>string</em> message) + </nobr> + <div class="jd-descrdiv"> + Sends the characters contained in message to this device, as if they + had been typed on the device's keyboard. This is equivalent to calling + <code><a href="#press">press()</a></code> for each keycode in <code>message</code> + using the key event type <code><a href="#ACTION_DOWN_AND_UP"></a>DOWN_AND_UP</code>. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#touch">wake</a> + </span> + () + </nobr> + <div class="jd-descrdiv"> + Wakes the screen of this device. + </div> + </td> + </tr> +</table> +<!-- ========= ENUM CONSTANTS DETAIL ======== --> +<h2>Constants</h2> +<A NAME="ACTION_DOWN"></a> +<div class="jd-details api"> + <h4 class="jd-details-title"> + <span class="normal"> + <em>string</em> + </span> + DOWN + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + <code><a href="#press">press()</a></code> or + <code><a href="#press">touch()</a></code> value. + Specifies that a DOWN event type should be sent to the device, corresponding to + pressing down on a key or touching the screen. + </p> + </div> + </div> +</div> +<A NAME="ACTION_UP"></A> +<div class="jd-details api"> + <h4 class="jd-details-title"> + <span class="normal"> + <em>string</em> + </span> + UP + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + <code><a href="#press">press()</a></code> or + <code><a href="#press">touch()</a></code> value. + Specifies that an UP event type should be sent to the device, corresponding to + releasing a key or lifting up from the screen. + </p> + </div> + </div> +</div> +<A NAME="ACTION_DOWN_AND_UP"></A> + +<div class="jd-details api"> + <h4 class="jd-details-title"> + <span class="normal"> + <em>string</em> + </span> + DOWN_AND_UP + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + <code><a href="#press">press()</a></code>, + <code><a href="#press">touch()</a></code> or + <code><a href="#type">type()</a></code> value. + Specifies that a DOWN event type followed by an UP event type should be sent to the + device, corresponding to typing a key or clicking the screen. + </p> + </div> + </div> +</div> +<!-- ========= METHOD DETAIL ======== --> +<!-- Public methods --> +<h2>Public Methods</h2> +<A NAME="broadcastIntent"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">broadcastIntent</span> + <span class="normal"> + ( + <em>string</em> uri, + <em>string</em> action, + <em>string</em> data, + <em>string</em> mimetype, + <em>iterable</em> categories + <em>dictionary</em> extras, + <em>component</em> component, + <em>iterable</em> flags) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Broadcasts an Intent to this device, as if the Intent were coming from an + application. See {@link android.content.Intent Intent} for more information about the + arguments. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>uri</th> + <td> + The URI for the Intent. + (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}). + </td> + </tr> + <tr> + <th>action</th> + <td> + The action for this Intent + (see {@link android.content.Intent#setAction(java.lang.String) Intent.setAction()}). + </td> + </tr> + <tr> + <th>data</th> + <td> + The data URI for this Intent + (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}). + </td> + </tr> + <tr> + <th>mimetype</th> + <td> + The MIME type for the Intent + (see {@link android.content.Intent#setType(java.lang.String) Intent.setType()}). + </td> + </tr> + <tr> + <th>categories</th> + <td> + An iterable data structure containing strings that define categories for this + Intent + (see + {@link android.content.Intent#addCategory(java.lang.String) Intent.addCategory()}). + </td> + </tr> + <tr> + <th>extras</th> + <td> + A dictionary of extra data for this Intent + (see {@link android.content.Intent#putExtra(java.lang.String,java.lang.String) + Intent.putExtra()} + for an example). + <p> + The key for each dictionary item should be a <em>string</em>. The item's value + can be any simple or structured data type. + </p> + </td> + </tr> + <tr> + <th>component</th> + <td> + The component for this Intent (see {@link android.content.ComponentName}). + Using this argument will direct the Intent to a specific class within a specific + Android package. + </td> + </tr> + <tr> + <th>flags</th> + <td> + An iterable data structure containing flags that control how the Intent is handled + (see {@link android.content.Intent#setFlags(int) Intent.setFlags()}). + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="drag"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">drag</span> + <span class="normal"> + ( + <em>tuple</em> start, + <em>tuple</em> end, + <em>float</em> duration, + <em>integer</em> steps) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Simulates a drag gesture (touch, hold, and move) on this device's screen. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>start</th> + <td> + The starting point of the drag gesture, in the form of a <em>tuple</em> + (x,y) where x and y are <em>integers</em>. + </td> + </tr> + <tr> + <th>end</th> + <td> + The end point of the drag gesture, in the form of a <em>tuple</em> (x,y) + where x and y are <em>integers</em>. + </td> + </tr> + <tr> + <th>duration</th> + <td>The duration of the drag gesture in seconds. The default is 1.0 seconds.</td> + </tr> + <tr> + <th>steps</th> + <td>The number of steps to take when interpolating points. The default is 10.</td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="getProperty"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>object</em> + </span> + <span class="sympad">getProperty</span> + <span class="normal"> + (<em>string</em> key) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Given the name of a system environment variable, returns its value for this device. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>key</th> + <td> + The name of the system environment variable. The available variable names are listed in + <a href="#table1">Table 1. Property variable names</a> at the end of this topic. + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + The value of the variable. The data format varies according to the variable requested. + </li> + </ul> + </div> + </div> +</div> +<A NAME="getSystemProperty"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>object</em> + </span> + <span class="sympad">getSystemProperty</span> + <span class="normal"> + (<em>string</em> key) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Synonym for <code><a href="#getProperty">getProperty()</a></code>. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>key</th> + <td> + The name of the system environment variable. The available variable names are listed in + <a href="#table1">Table 1. Property Variable Names</a>. + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + The value of the variable. The data format varies according to the variable requested. + </li> + </ul> + </div> + </div> +</div> +<A NAME="installPackage"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">installPackage</span> + <span class="normal"> + (<em>string</em> path) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Installs the Android application or test package contained in packageFile + onto this device. If the application or test package is already installed, it is + replaced. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>path</th> + <td> + The fully-qualified path and filename of the <code>.apk</code> file to install. + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="instrument"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>dictionary</em> + </span> + <span class="sympad">instrument</span> + <span class="normal"> + ( + <em>string</em> className, + <em>dictionary</em> args) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Runs the specified component with Android instrumentation, and returns the results + in a dictionary whose exact format is dictated by the component being run. The + component must already be present on this device. + </p> + <p> + Use this method to start a test case that uses one of Android's test case classes. + See <a href="{@docRoot}guide/topics/testing/testing_android.html">Testing + Fundamentals</a> to learn more about unit testing with the Android testing + framework. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>className</th> + <td> + The name of an Android component that is already installed on this device, in the + standard form packagename/classname, where packagename is the + Android package name of a <code>.apk</code> file on this device, and + classname is the class name of an Android component (Activity, + ContentProvider, Service, or BroadcastReceiver) in that file. Both + packagename and classname must be fully qualified. See + {@link android.content.ComponentName} for more details. + </td> + </tr> + <tr> + <th>args</th> + <td> + A dictionary containing flags and their values. These are passed to the component as it + is started. If the flag does not take a value, set its dictionary value to an empty + string. + </td> + </tr> + </table> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + <p> + A dictionary containing the component's output. The contents of the dictionary + are defined by the component itself. + </p> + <p> + If you use {@link android.test.InstrumentationTestRunner} as the class name in + the componentName argument, then the result dictionary contains + the single key "stream". The value of "stream" is a <em>string</em> containing + the test output, as if <code>InstrumentationTestRunner</code> was run from the + command line. The format of this output is described in + <a href="{@docRoot}guide/developing/testing/testing_otheride.html"> + Testing in Other IDEs</a>. + </p> + </li> + </ul> + </div> + </div> + </div> +</div> +<A NAME="press"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">press</span> + <span class="normal"> + (<em>string</em> name, + <em>integer</em> type) + </span> + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + Sends the key event specified by <code>type</code> to the key specified by + <code>keycode</code>. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>name</th> + <td> + The name of the keycode to send. See {@link android.view.KeyEvent} for a list of + keycode names. Use the keycode name, not its integer value. + </td> + </tr> + <tr> + <th>type</th> + <td> + The type of key event to send. The allowed values are <code><a href="#ACTION_DOWN"> + DOWN</a></code>, <code><a href="#ACTION_UP">UP</a></code>, and + <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>. + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="reboot"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">reboot</span> + <span class="normal"> + (<em>string</em> bootloadType) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Reboots this device into the bootloader specified by <code>bootloadType</code>. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>into</th> + <td> + The type of bootloader to reboot into. The allowed values are + "bootloader", "recovery", or "None". + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="removePackage"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">removePackage</span> + <span class="normal"> + (<em>string</em> package) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Deletes the specified package from this device, including its data and cache. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>package</th> + <td> + The Android package name of an <code>.apk</code> file on this device. + </td> + </table> + </div> + </div> +</div> +<A NAME="shell"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>object</em> + </span> + <span class="sympad">shell</span> + <span class="normal"> + (<em>string</em> cmd) + </span> + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + Executes an <code>adb</code> shell command and returns the result, if any. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>cmd</th> + <td> + The command to execute in the <code>adb</code> shell. The form of these commands is + described in the topic <a href="{@docRoot}guide/developing/tools/adb.html">Android + Debug Bridge</a>. + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + The results of the command, if any. The format of the results is determined by the + command. + </li> + </ul> + </div> + </div> +</div> +<A NAME="startActivity"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">startActivity</span> + <span class="normal"> + ( + <em>string</em> uri, + <em>string</em> action, + <em>string</em> data, + <em>string</em> mimetype, + <em>iterable</em> categories + <em>dictionary</em> extras, + <em>component</em> component, + <em>iterable</em> flags) + </span> + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + Starts an Activity on this device by sending an Intent constructed from the + supplied arguments. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>uri</th> + <td> + The URI for the Intent. + (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}). + </td> + </tr> + <tr> + <th>action</th> + <td> + The action for the Intent + (see {@link android.content.Intent#setAction(java.lang.String) Intent.setAction()}). + </td> + </tr> + <tr> + <th>data</th> + <td> + The data URI for the Intent + (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}). + </td> + </tr> + <tr> + <th>mimetype</th> + <td> + The MIME type for the Intent + (see {@link android.content.Intent#setType(java.lang.String) Intent.setType()}). + </td> + </tr> + <tr> + <th>categories</th> + <td> + An iterable data structure containing strings that define categories for the + Intent + (see + {@link android.content.Intent#addCategory(java.lang.String) Intent.addCategory()}). + </td> + </tr> + <tr> + <th>extras</th> + <td> + A dictionary of extra data for the Intent + (see + {@link android.content.Intent#putExtra(java.lang.String,java.lang.String) + Intent.putExtra()} + for an example). + <p> + The key for each dictionary item should be a <em>string</em>. The item's value + can be any simple or structured data type. + </p> + </td> + </tr> + <tr> + <th>component</th> + <td> + The component for the Intent + (see {@link android.content.ComponentName}). Using this argument will direct the + Intent to a specific class within a specific Android package. + </td> + </tr> + <tr> + <th>flags</th> + <td> + An iterable data structure containing flags that control how the Intent is handled + (see {@link android.content.Intent#setFlags(int) Intent.setFlags()}). + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="takeSnapshot"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyImage.html"> + MonkeyImage + </a> + </code> + </span> + <span class="sympad">takeSnapshot</span> + <span class="normal"> + () + </span> + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + Captures the entire screen buffer of this device, yielding a + screen capture of the current display. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + A <a href="{@docRoot}guide/developing/tools/MonkeyImage.html"> + MonkeyImage</a> object containing the image of the current display. + </li> + </ul> + </div> + </div> +</div> +<A NAME="touch"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">touch</span> + <span class="normal"> + ( + <em>integer</em> x, + <em>integer</em> y, + <em>string</em> type) + </span> + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + Sends a touch event specified by type to the screen location specified + by x and y. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>x</th> + <td> + The horizontal position of the touch in actual device pixels, starting from the left of + the screen in its current orientation. + </td> + </tr> + <tr> + <th>y</th> + <td> + The vertical position of the touch in actual device pixels, starting from the top of + the screen in its current orientation. + </td> + </tr> + <tr> + <th>type</th> + <td> + The type of key event to send. The allowed values are <code><a href="#ACTION_DOWN"> + DOWN</a></code>, <code><a href="#ACTION_UP">UP</a></code>, and + <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>. + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="type"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">type</span> + <span class="normal"> + (<em>string</em> message) + </span> + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + Sends the characters contained in message to this device, as if they + had been typed on the device's keyboard. This is equivalent to calling + <code><a href="#press">press()</a></code> for each keycode in <code>message</code> + using the key event type <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>message</th> + <td> + A string containing the characters to send. + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="wake"></A> +<div class="jd-details api"> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">wake</span> + <span class="normal"> + () + </span> + </h4> + <div class="jd-details-descr"> + <div class="jd-tagdata jd-tagdescr"> + <p> + Wakes the screen of this device. + </p> + </div> + </div> +</div> +<hr></hr> +<h2>Appendix</h2> + <p class="table-caption" id="table1"> + <strong>Table 1.</strong>Property variable names used with + <span class="sympad"><a href="#getProperty">getProperty()</a></span> and + <span class="sympad"><a href="#getSystemProperty">getSystemProperty()</a></span>. + </p> + <table> + <tr> + <th> + Property Group + </th> + <th> + Property + </th> + <th> + Description + </th> + <th> + Notes + </th> + </tr> + <tr> + <td rowspan="17"><code>build</code></td> + <td><code>board</code></td> + <td>Code name for the device's system board</td> + <td rowspan="17"> + See {@link android.os.Build} + </td> + </tr> + <tr> + <td><code>brand</code></td> + <td>The carrier or provider for which the OS is customized.</td> + </tr> + <tr> + <td><code>device</code></td> + <td>The device design name.</td> + </tr> + <tr> + <td><code>fingerprint</code></td> + <td>A unique identifier for the currently-running build.</td> + </tr> + <tr> + <td><code>host</code></td> + <td></td> + </tr> + <tr> + <td><code>ID</code></td> + <td>A changelist number or label.</td> + </tr> + <tr> + <td><code>model</code></td> + <td>The end-user-visible name for the device.</td> + </tr> + <tr> + <td><code>product</code></td> + <td>The overall product name.</td> + </tr> + <tr> + <td><code>tags</code></td> + <td>Comma-separated tags that describe the build, such as "unsigned" and "debug".</td> + </tr> + <tr> + <td><code>type</code></td> + <td>The build type, such as "user" or "eng".</td> + </tr> + <tr> + <td><code>user</code></td> + <td></td> + </tr> + <tr> + <td><code>CPU_ABI</code></td> + <td> + The name of the native code instruction set, in the form CPU type plus + ABI convention. + </td> + </tr> + <tr> + <td><code>manufacturer</code></td> + <td>The product/hardware manufacturer.</td> + </tr> + <tr> + <td><code>version.incremental</code></td> + <td> + The internal code used by the source control system to represent this version + of the software. + </td> + </tr> + <tr> + <td><code>version.release</code></td> + <td>The user-visible name of this version of the software.</td> + </tr> + <tr> + <td><code>version.sdk</code></td> + <td>The user-visible SDK version associated with this version of the OS.</td> + </tr> + <tr> + <td><code>version.codename</code></td> + <td> + The current development codename, or "REL" if this version of the software has been + released. + </td> + </tr> + <tr> + <td rowspan="3"><code>display</code></td> + <td><code>width</code></td> + <td>The device's display width in pixels.</td> + <td rowspan="3"> + See + {@link android.util.DisplayMetrics} for details. + </td> + </tr> + <tr> + <td><code>height</code></td> + <td>The device's display height in pixels.</td> + </tr> + <tr> + <td><code>density</code></td> + <td> + The logical density of the display. This is a factor that scales + DIP (Density-Independent Pixel) units to the device's resolution. DIP is adjusted so + that 1 DIP is equivalent to one pixel on a 160 pixel-per-inch display. For example, + on a 160-dpi screen, density = 1.0, while on a 120-dpi screen, density = .75. + <p> + The value does not exactly follow the real screen size, but is adjusted to + conform to large changes in the display DPI. See + {@link android.util.DisplayMetrics#density} for more details. + </p> + </td> + </tr> + <tr> + <td rowspan="6"><code>am.current</code></td> + <td><code>package</code></td> + <td>The Android package name of the currently running package.</td> + <td rowspan="6"> + The <code>am.current</code> keys return information about the currently-running + Activity. + </td> + </tr> + <tr> + <td><code>action</code></td> + <td> + The current activity's action. This has the same format as the <code>name</code> + attribute of the <code>action</code> element in a package manifest. + </td> + </tr> + <tr> + <td><code>comp.class</code></td> + <td> + The class name of the component that started the current Activity. See + <code><a href="#comppackage">comp.package</a></code> for more details.</td> + </tr> + <tr> + <td><a name="comppackage"><code>comp.package</code></a></td> + <td> + The package name of the component that started the current Activity. A component + is specified by a package name and the name of class that the package contains. + </td> + </tr> + <tr> + <td><code>data</code></td> + <td>The data (if any) contained in the Intent that started the current Activity.</td> + </tr> + <tr> + <td><code>categories</code></td> + <td>The categories specified by the Intent that started the current Activity.</td> + </tr> + <tr> + <td rowspan="3"><code>clock</code></td> + <td><code>realtime</code></td> + <td> + The number of milliseconds since the device rebooted, including deep-sleep + time. + </td> + <td rowspan="3"> + See {@link android.os.SystemClock} for more information. + </td> + </tr> + <tr> + <td><code>uptime</code></td> + <td> + The number of milliseconds since the device rebooted, <em>not</em> including + deep-sleep time + </td> + </tr> + <tr> + <td><code>millis</code></td> + <td>current time since the UNIX epoch, in milliseconds.</td> + </tr> + </table> diff --git a/docs/html/guide/developing/tools/MonkeyImage.jd b/docs/html/guide/developing/tools/MonkeyImage.jd new file mode 100644 index 0000000..ae85cb5 --- /dev/null +++ b/docs/html/guide/developing/tools/MonkeyImage.jd @@ -0,0 +1,435 @@ +page.title=MonkeyImage +@jd:body +<style> + h4.jd-details-title {background-color: #DEE8F1;} +</style> + +<p> + A monkeyrunner class to hold an image of the device or emulator's screen. The image is + copied from the screen buffer during a screenshot. This object's methods allow you to + convert the image into various storage formats, write the image to a file, copy parts of + the image, and compare this object to other <code>MonkeyImage</code> objects. +</p> +<p> + You do not need to create new instances of <code>MonkeyImage</code>. Instead, use +<code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html#takeSnapshot"> +MonkeyDevice.takeSnapshot()</a></code> to create a new instance from a screenshot. For example, use: +</p> +<pre> +newimage = MonkeyDevice.takeSnapshot() +</pre> +<h2>Summary</h2> +<table id="pubmethods" class="jd-sumtable"> + <tr> + <th colspan="12" style="background-color: #E2E2E2">Methods</th> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>string</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#convertToBytes">convertToBytes</a> + </span> + (<em>string</em> format) + </nobr> + <div class="jd-descrdiv"> + Converts the current image to a particular format and returns it as a + <em>string</em> that you can then access as an <em>iterable</em> of binary bytes. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>tuple</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#getRawPixel">getRawPixel</a> + </span> + (<em>integer</em> x, + <em>integer</em> y) + </nobr> + <div class="jd-descrdiv"> + Returns the single pixel at the image location (x,y), as an + a <em>tuple</em> of <em>integer</em>, in the form (a,r,g,b). + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>integer</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#getRawPixelInt">getRawPixelInt</a> + </span> + (<em>integer</em> x, + <em>integer</em> y) + </nobr> + <div class="jd-descrdiv"> + Returns the single pixel at the image location (x,y), as + a 32-bit <em>integer</em>. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a> + </code> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#getSubImage">getSubImage</a> + </span> + (<em>tuple</em> rect) + </nobr> + <div class="jd-descrdiv"> + Creates a new <code>MonkeyImage</code> object from a rectangular selection of the + current image. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>boolean</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#sameAs">sameAs</a> + </span> + (<code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code> + other, + <em>float</em> percent) + </nobr> + <div class="jd-descrdiv"> + Compares this <code>MonkeyImage</code> object to another and returns the result of + the comparison. The <code>percent</code> argument specifies the percentage + difference that is allowed for the two images to be "equal". + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>void</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#writeToFile">writeToFile</a> + </span> + (<em>string</em> path, + <em>string</em> format) + </nobr> + <div class="jd-descrdiv"> + Writes the current image to the file specified by <code>filename</code>, in the + format specified by <code>format</code>. + </div> + </td> + </tr> +</table> +<!-- ========= METHOD DETAIL ======== --> +<!-- Public methods --> +<h2>Public Methods</h2> +<A NAME="convertToBytes"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>string</em> + </span> + <span class="sympad">convertToBytes</span> + <span class="normal"> + ( + <em>string</em> format) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Converts the current image to a particular format and returns it as a <em>string</em> + that you can then access as an <em>iterable</em> of binary bytes. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>format</th> + <td> + The desired output format. All of the common raster output formats are supported. + The default value is "png" (Portable Network Graphics). + </td> + </tr> + </table> + </div> +</div> +</div> +<A NAME="getRawPixel"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>tuple</em> + </span> + <span class="sympad">getRawPixel</span> + <span class="normal"> + (<em>integer</em> x, + <em>integer</em> y) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Returns the single pixel at the image location (x,y), as an + a <em>tuple</em> of <em>integer</em>, in the form (a,r,g,b). + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>x</th> + <td> + The horizontal position of the pixel, starting with 0 at the left of the screen in the + orientation it had when the screenshot was taken. + </td> + </tr> + <tr> + <th>y</th> + <td> + The vertical position of the pixel, starting with 0 at the top of the screen in the + orientation it had when the screenshot was taken. + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + A tuple of integers representing the pixel, in the form (a,r,g,b) where + a is the alpha channel value, and r, g, and b are the red, green, and blue values, + respectively. + </li> + </ul> + </div> + </div> +</div> +<A NAME="getRawPixelInt"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>tuple</em> + </span> + <span class="sympad">getRawPixelInt</span> + <span class="normal"> + (<em>integer</em> x, + <em>integer</em> y) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Returns the single pixel at the image location (x,y), as an + an <em>integer</em>. Use this method to economize on memory. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>x</th> + <td> + The horizontal position of the pixel, starting with 0 at the left of the screen in the + orientation it had when the screenshot was taken. + </td> + </tr> + <tr> + <th>y</th> + <td> + The vertical position of the pixel, starting with 0 at the top of the screen in the + orientation it had when the screenshot was taken. + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + The a,r,g, and b values of the pixel as 8-bit values combined into a 32-bit + integer, with a as the leftmost 8 bits, r the next rightmost, and so forth. + </li> + </ul> + </div> + </div> +</div> +<A NAME="getSubImage"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a> + </code> + </span> + <span class="sympad">getSubImage</span> + <span class="normal"> + (<em>tuple</em> rect) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Creates a new <code>MonkeyImage</code> object from a rectangular selection of the + current image. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>rect</th> + <td> + A tuple (x, y, w, h) specifying the selection. x and y specify the 0-based pixel + position of the upper left-hand corner of the selection. w specifies the width of the + region, and h specifies its height, both in units of pixels. + <p> + The image's orientation is the same as the screen orientation at the time the + screenshot was made. + </p> + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + A new <code>MonkeyImage</code> object containing the selection. + </li> + </ul> + </div> + </div> +</div> +<A NAME="sameAs"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>boolean</em> + </span> + <span class="sympad">sameAs</span> + <span class="normal"> + ( + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a> + </code> otherImage, + <em>float</em> percent + ) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Compares this <code>MonkeyImage</code> object to another and returns the result of + the comparison. The <code>percent</code> argument specifies the percentage + difference that is allowed for the two images to be "equal". + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>other</th> + <td> + Another <code>MonkeyImage</code> object to compare to this one. + </td> + </tr> + <tr> + <th> + percent + </th> + <td> + A float in the range 0.0 to 1.0, inclusive, indicating + the percentage of pixels that need to be the same for the method to return + <code>true</code>. The default is 1.0, indicating that all the pixels + must match. + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + Boolean <code>true</code> if the images match, or boolean <code>false</code> otherwise. + </li> + </ul> + </div> + </div> +</div> +<A NAME="writeToFile"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">writeToFile</span> + <span class="normal"> + (<em>string</em> filename, + <em>string</em> format) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Writes the current image to the file specified by <code>filename</code>, in the + format specified by <code>format</code>. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>path</th> + <td> + The fully-qualified filename and extension of the output file. + </td> + </tr> + <tr> + <th> + format + </th> + <td> + The output format to use for the file. If no format is provided, then the + method tries to guess the format from the filename's extension. If no + extension is provided and no format is specified, then the default format of + "png" (Portable Network Graphics) is used. + </td> + </tr> + </table> + </div> + </div> +</div> diff --git a/docs/html/guide/developing/tools/MonkeyRunner.jd b/docs/html/guide/developing/tools/MonkeyRunner.jd new file mode 100644 index 0000000..871e06d --- /dev/null +++ b/docs/html/guide/developing/tools/MonkeyRunner.jd @@ -0,0 +1,445 @@ +page.title=MonkeyRunner +@jd:body +<style> + h4.jd-details-title {background-color: #DEE8F1;} +</style> +<p> + A monkeyrunner class that contains static utility methods. +</p> +<h2>Summary</h2> +<table id="pubmethods" class="jd-sumtable"> + <tr> + <th colspan="12" style="background-color: #E2E2E2">Methods</th> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#alert">alert</a> + </span> + (<em>string</em> message, + <em>string</em> title, + <em>string</em> okTitle) + </nobr> + <div class="jd-descrdiv"> + Displays an alert dialog to the process running the current + program. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>integer</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#choice">choice</a> + </span> + (<em>string</em> message, + <em>iterable</em> choices, + <em>string</em> title) + </nobr> + <div class="jd-descrdiv"> + Displays a dialog with a list of choices to the process running the current program. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#help">help</a> + </span> + (<em>string</em> format) + </nobr> + <div class="jd-descrdiv"> + Displays the monkeyrunner API reference in a style similar to that of Python's + <code>pydoc</code> tool, using the specified format. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <em>string</em> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#input">input</a> + </span> + (<em>string</em> message, + <em>string</em> initialValue, + <em>string</em> title, + <em>string</em> okTitle, + <em>string</em> cancelTitle) + </nobr> + <div class="jd-descrdiv"> + Displays a dialog that accepts input. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + void + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#sleep">sleep</a> + </span> + (<em>float</em> seconds) + </nobr> + <div class="jd-descrdiv"> + Pauses the current program for the specified number of seconds. + </div> + </td> + </tr> + <tr class="api" > + <td class="jd-typecol"> + <nobr> + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a> + </code> + </nobr> + </td> + <td class="jd-linkcol" width="100%"> + <nobr> + <span class="sympad"> + <a href="#waitForConnection">waitForConnection</a> + </span> + (<em>float</em> timeout, + <em>string</em> deviceId) + </nobr> + <div class="jd-descrdiv"> + Tries to make a connection between the <code>monkeyrunner</code> backend and the + specified device or emulator. + </div> + </td> + </tr> +</table> +<!-- ========= METHOD DETAIL ======== --> +<!-- Public methods --> +<h2>Public Methods</h2> +<A NAME="alert"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>string</em> + </span> + <span class="sympad">alert</span> + <span class="normal"> + ( + <em>string</em> message, + <em>string</em> title, + <em>string</em> okTitle) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Displays an alert dialog to the process running the current + program. The dialog is modal, so the program pauses until the user clicks the dialog's + button. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>message</th> + <td> + The message to display in the dialog. + </td> + </tr> + <tr> + <th>title</th> + <td> + The dialog's title. The default value is "Alert". + </td> + </tr> + <tr> + <th>okTitle</th> + <td> + The text displayed in the dialog button. The default value is "OK". + </td> + </tr> + </table> + </div> +</div> +</div> +<A NAME="choice"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>integer</em> + </span> + <span class="sympad">choice</span> + <span class="normal"> + (<em>string</em> message, + <em>iterable</em> choices, + <em>string</em> title) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Displays a dialog with a list of choices to the process running the current program. The + dialog is modal, so the program pauses until the user clicks one of the dialog's + buttons. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>message</th> + <td> + The prompt message displayed in the dialog. + </td> + </tr> + <tr> + <th>choices</th> + <td> + A Python iterable containing one or more objects that are displayed as strings. The + recommended form is an array of strings. + </td> + </tr> + <tr> + <th> + title + </th> + <td> + The dialog's title. The default is "Input". + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + If the user makes a selection and clicks the "OK" button, the method returns + the 0-based index of the selection within the iterable. + If the user clicks the "Cancel" button, the method returns -1. + </li> + </ul> + </div> + </div> +</div> +<A NAME="help"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">help</span> + <span class="normal"> + (<em>string</em> format) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Displays the monkeyrunner API reference in a style similar to that of Python's + <code>pydoc</code> tool, using the specified format. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>format</th> + <td> + The markup format to use in the output. The possible values are "text" for plain text + or "html" for HTML. + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="input"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <em>string</em> + </span> + <span class="sympad">input</span> + <span class="normal"> + (<em>string</em> message + <em>string</em> initialValue, + <em>string</em> title, + <em>string</em> okTitle, + <em>string</em> cancelTitle) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Displays a dialog that accepts input and returns it to the program. The dialog is + modal, so the program pauses until the user clicks one of the dialog's buttons. + </p> + <p> + The dialog contains two buttons, one of which displays the okTitle value + and the other the cancelTitle value. If the user clicks the okTitle button, + the current value of the input box is returned. If the user clicks the cancelTitle + button, an empty string is returned. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>message</th> + <td> + The prompt message displayed in the dialog. + </td> + </tr> + <tr> + <th>initialValue</th> + <td> + The initial value to display in the dialog. The default is an empty string. + </td> + </tr> + <tr> + <th>title</th> + <td> + The dialog's title. The default is "Input". + </td> + </tr> + <tr> + <th>okTitle</th> + <td> + The text displayed in the okTitle button. The default is "OK". + </td> + </tr> + <tr> + <th>cancelTitle</th> + <td> + The text displayed in the cancelTitle button. The default is "Cancel". + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + If the user clicks the okTitle button, then the method returns the current value of + the dialog's input box. If the user clicks the cancelTitle button, the method returns + an empty string. + </li> + </ul> + </div> + </div> +</div> +<A NAME="sleep"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + void + </span> + <span class="sympad">sleep</span> + <span class="normal"> + ( + <em>float</em> seconds + ) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Pauses the current program for the specified number of seconds. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>seconds</th> + <td> + The number of seconds to pause. + </td> + </tr> + </table> + </div> + </div> +</div> +<A NAME="waitForConnection"></A> +<div class="jd-details api "> + <h4 class="jd-details-title"> + <span class="normal"> + <code> + <a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a> + </code> + </span> + <span class="sympad">waitForConnection</span> + <span class="normal"> + (<em>float</em> timeout, + <em>string</em> deviceId) + </span> + </h4> + <div class="jd-details-descr"> + + <div class="jd-tagdata jd-tagdescr"> + <p> + Tries to make a connection between the <code>monkeyrunner</code> backend and the + specified device or emulator. + </p> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Arguments</h5> + <table class="jd-tagtable"> + <tr> + <th>timeout</th> + <td> + The number of seconds to wait for a connection. The default is to wait forever. + </td> + </tr> + <tr> + <th> + deviceId + </th> + <td> + A regular expression that specifies the serial number of the device or emulator. See + the topic + <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a> + for a description of device and emulator serial numbers. + </td> + </tr> + </table> + </div> + <div class="jd-tagdata"> + <h5 class="jd-tagtitle">Returns</h5> + <ul class="nolist"> + <li> + A <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code> + instance for the device or emulator. Use this object to control and communicate with the + device or emulator. + </li> + </ul> + </div> + </div> +</div> diff --git a/docs/html/guide/developing/tools/index.jd b/docs/html/guide/developing/tools/index.jd index 6e9fde1..0e10377 100644 --- a/docs/html/guide/developing/tools/index.jd +++ b/docs/html/guide/developing/tools/index.jd @@ -3,27 +3,27 @@ page.title=Tools Overview <img src="{@docRoot}assets/images/android_wrench.png" alt="" align="right"> -<p>The Android SDK includes a variety of custom tools that help you develop mobile -applications on the Android platform. The most important of these are the Android -Emulator and the Android Development Tools plugin for Eclipse, but the SDK also -includes a variety of other tools for debugging, packaging, and installing your +<p>The Android SDK includes a variety of custom tools that help you develop mobile +applications on the Android platform. The most important of these are the Android +Emulator and the Android Development Tools plugin for Eclipse, but the SDK also +includes a variety of other tools for debugging, packaging, and installing your applications on the emulator. </p> - + <dl> <dt><a href="adt.html">Android Development Tools Plugin</a> (for the Eclipse IDE)</dt> - <dd>The ADT plugin adds powerful extensions to the Eclipse integrated environment, - making creating and debugging your Android applications easier and faster. If you - use Eclipse, the ADT plugin gives you an incredible boost in developing Android + <dd>The ADT plugin adds powerful extensions to the Eclipse integrated environment, + making creating and debugging your Android applications easier and faster. If you + use Eclipse, the ADT plugin gives you an incredible boost in developing Android applications.</dd> <dt><a href="emulator.html">Android Emulator</a></dt> - <dd>A QEMU-based device-emulation tool that you can use to design, + <dd>A QEMU-based device-emulation tool that you can use to design, debug, and test your applications in an actual Android run-time environment. </dd> <dt><a href="avd.html">Android Virtual Devices (AVDs)</a></dt> <dd>Virtual device configurations that you create, to model device characteristics in the Android Emulator. In each configuration, you can specify the Android platform to run, the hardware options, and the - emulator skin to use. Each AVD functions as an independent device with + emulator skin to use. Each AVD functions as an independent device with it's own storage for user data, SD card, and so on. </dd> <dt><a href="hierarchy-viewer.html">Hierarchy Viewer</a></dt> @@ -37,53 +37,53 @@ applications on the emulator. </p> efficiency. </dd> - <dt><a href="draw9patch.html">Draw 9-patch</a></dt> - <dd>The Draw 9-patch tool allows you to easily create a - {@link android.graphics.NinePatch} graphic using a WYSIWYG editor. It also previews stretched - versions of the image, and highlights the area in which content is allowed. - </dd> + <dt><a href="draw9patch.html">Draw 9-patch</a></dt> + <dd>The Draw 9-patch tool allows you to easily create a + {@link android.graphics.NinePatch} graphic using a WYSIWYG editor. It also previews stretched + versions of the image, and highlights the area in which content is allowed. + </dd> - <dt><a href="ddms.html" >Dalvik Debug Monitor + <dt><a href="ddms.html" >Dalvik Debug Monitor Service</a> (ddms)</dt> - <dd>Integrated with Dalvik, the Android platform's custom VM, this tool - lets you manage processes on an emulator or device and assists in debugging. - You can use it to kill processes, select a specific process to debug, - generate trace data, view heap and thread information, take screenshots - of the emulator or device, and more. </dd> - + <dd>Integrated with Dalvik, the Android platform's custom VM, this tool + lets you manage processes on an emulator or device and assists in debugging. + You can use it to kill processes, select a specific process to debug, + generate trace data, view heap and thread information, take screenshots + of the emulator or device, and more. </dd> + <dt><a href="adb.html" >Android Debug Bridge</a> (adb)</dt> - <dd>The adb tool lets you install your application's .apk files on an - emulator or device and access the emulator or device from a command line. - You can also use it to link a standard debugger to application code running + <dd>The adb tool lets you install your application's .apk files on an + emulator or device and access the emulator or device from a command line. + You can also use it to link a standard debugger to application code running on an Android emulator or device.</dd> - <dt><a href="aapt.html">Android Asset + <dt><a href="aapt.html">Android Asset Packaging Tool</a> (aapt)</dt> - <dd>The aapt tool lets you create .apk files containing the binaries and + <dd>The aapt tool lets you create .apk files containing the binaries and resources of Android applications.</dd> - <dt><a href="aidl.html" >Android Interface + <dt><a href="aidl.html" >Android Interface Description Language</a> (aidl)</dt> <dd>Lets you generate code for an interprocess interface, such as what a service might use.</dd> <dt><a href="adb.html#sqlite">sqlite3</a></dt> - <dd>Included as a convenience, this tool lets you access the SQLite data + <dd>Included as a convenience, this tool lets you access the SQLite data files created and used by Android applications.</dd> <dt><a href="traceview.html" >Traceview</a></dt> - <dd> This tool produces graphical analysis views of trace log data that you + <dd> This tool produces graphical analysis views of trace log data that you can generate from your Android application. </dd> <dt><a href="othertools.html#mksdcard">mksdcard</a></dt> - <dd>Helps you create a disk image that you can use with the emulator, + <dd>Helps you create a disk image that you can use with the emulator, to simulate the presence of an external storage card (such as an SD card).</dd> <dt><a href="othertools.html#dx">dx</a></dt> - <dd>The dx tool rewrites .class bytecode into Android bytecode + <dd>The dx tool rewrites .class bytecode into Android bytecode (stored in .dex files.)</dd> - <dt><a href="monkey.html">UI/Application + <dt><a href="monkey.html">UI/Application Exerciser Monkey</a></dt> <dd>The Monkey is a program that runs on your emulator or device and generates pseudo-random streams of user events such as clicks, touches, or gestures, as well as a number of system- @@ -92,9 +92,9 @@ efficiency. <dt><a href="othertools.html#android">android</a></dt> <dd>A script that lets you manage AVDs and generate <a - href="http://ant.apache.org/" title="Ant">Ant</a> build files that + href="http://ant.apache.org/" title="Ant">Ant</a> build files that you can use to compile your Android applications. </dd> - + <dt><a href="zipalign.html">zipalign</a></dt> <dd>An important .apk optimization tool. This tool ensures that all uncompressed data starts with a particular alignment relative to the start of the file. This should always be used diff --git a/docs/html/guide/developing/tools/monkeyrunner_concepts.jd b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd new file mode 100644 index 0000000..1838905 --- /dev/null +++ b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd @@ -0,0 +1,308 @@ +page.title=monkeyrunner +@jd:body + +<div id="qv-wrapper"> + <div id="qv"> + <h2>In this document</h2> + <ol> + <li> + <a href="#SampleProgram">A Simple monkeyrunner Program</a> + </li> + <li> + <a href="#APIClasses">The monkeyrunner API</a> + </li> + <li> + <a href="#RunningMonkeyRunner">Running monkeyrunner</a> + </li> + <li> + <a href="#Help">monkeyrunner Built-in Help</a> + </li> + <li> + <a href="#Plugins">Extending monkeyrunner with Plugins</a> + </li> + </ol> + <h2>See Also</h2> + <ol> + <li> + <a href="{@docRoot}guide/topics/testing/testing_android.html">Testing Fundamentals</a> + </li> + </ol> + </div> +</div> +<p> + The monkeyrunner tool provides an API for writing programs that control an Android device + or emulator from outside of Android code. With monkeyrunner, you can write a Python program + that installs an Android application or test package, runs it, sends keystrokes to it, + takes screenshots of its user interface, and stores screenshots on the workstation. The + monkeyrunner tool is primarily designed to test applications and devices at the + functional/framework level and for running unit test suites, but you are free to use it for + other purposes. +</p> +<p> + The monkeyrunner tool is not related to the + <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>, + also known as the <code>monkey</code> tool. The <code>monkey</code> tool runs in an + <code><a href="{@docRoot}guide/developing/tools/adb.html">adb</a></code> shell directly on the + device or emulator and generates pseudo-random streams of user and system events. In comparison, + the monkeyrunner tool controls devices and emulators from a workstation by sending specific + commands and events from an API. +</p> +<p> + The monkeyrunner tool provides these unique features for Android testing: +</p> +<ul> + <li> + Multiple device control: The monkeyrunner API can apply one or more + test suites across multiple devices or emulators. You can physically attach all the devices + or start up all the emulators (or both) at once, connect to each one in turn + programmatically, and then run one or more tests. You can also start up an emulator + configuration programmatically, run one or more tests, and then shut down the emulator. + </li> + <li> + Functional testing: monkeyrunner can run an automated start-to-finish test of an Android + application. You provide input values with keystrokes or touch events, and view the results + as screenshots. + </li> + <li> + Regression testing - monkeyrunner can test application stability by running an application + and comparing its output screenshots to a set of screenshots that are known to be correct. + </li> + <li> + Extensible automation - Since monkeyrunner is an API toolkit, you can develop an entire + system of Python-based modules and programs for controlling Android devices. Besides using + the monkeyrunner API itself, you can use the standard Python + <code><a href="http://docs.python.org/library/os.html">os</a></code> and + <code><a href="http://docs.python.org/library/subprocess.html">subprocess</a></code> + modules to call Android tools such as + <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a>. + <p> + You can also add your own classes to the monkeyrunner API. This is described + in more detail in the section + <a href="#Plugins">Extending monkeyrunner with plugins</a>. + </p> + </li> +</ul> +<p> + The monkeyrunner tool uses <a href="http://www.jython.org/">Jython</a>, a + implementation of Python that uses the Java programming language. Jython allows the + monkeyrunner API to interact easily with the Android framework. With Jython you can + use Python syntax to access the constants, classes, and methods of the API. +</p> + +<h2 id="SampleProgram">A Simple monkeyrunner Program</h2> +<p> + Here is a simple monkeyrunner program that connects to a device, creating a + <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code> + object. Using the <code>MonkeyDevice</code> object, the program installs an Android application + package, runs one of its activities, and sends key events to the activity. + The program then takes a screenshot of the result, creating a + <code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code> object. + From this object, the program writes out a <code>.png</code> file containing the screenshot. +</p> +<pre> +# Imports the monkeyrunner modules used by this program +from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice + +# Connects to the current device, returning a MonkeyDevice object +device = MonkeyRunner.waitForConnection() + +# Installs the Android package. Notice that this method returns a boolean, so you can test +# to see if the installation worked. +device.installPackage('myproject/bin/MyApplication.apk') + +# Runs an activity in the application +device.startActivity(component='com.example.android.myapplication.MainActivity') + +# Presses the Menu button +device.press('KEYCODE_MENU','DOWN_AND_UP') + +# Takes a screenshot +result = device.takeSnapShot + +# Writes the screenshot to a file +result.writeToFile('myproject/shot1.png','png') +</pre> + +<h2 id="APIClasses">The monkeyrunner API</h2> +<p> + The monkeyrunner API is contained in three modules in the package + <code>com.android.monkeyrunner</code>: +</p> +<ul> + <li> + <code><a href="{@docRoot}guide/developing/tools/MonkeyRunner.html">MonkeyRunner</a></code>: + A class of utility methods for monkeyrunner programs. This class provides a method for + connecting monkeyrunner to a device or emulator. It also provides methods for + creating UIs for a monkeyrunner program and for displaying the built-in help. + </li> + <li> + <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code>: + Represents a device or emulator. This class provides methods for installing and + uninstalling packages, starting an Activity, and sending keyboard or touch events to an + application. You also use this class to run test packages. + </li> + <li> + <code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code>: + Represents a screen capture image. This class provides methods for capturing screens, + converting bitmap images to various formats, comparing two MonkeyImage objects, and + writing an image to a file. + </li> +</ul> +<p> + In a Python program, you access each class as a Python module. The monkeyrunner tool + does not import these modules automatically. To import a module, use the + Python <code>from</code> statement: +</p> +<pre> +from com.android.monkeyrunner import <module> +</pre> +<p> + where <code><module></code> is the class name you want to import. You can import more + than one module in the same <code>from</code> statement by separating the module names with + commas. +</p> +<h2 id="RunningMonkeyRunner">Running monkeyrunner</h2> +<p> + You can either run monkeyrunner programs from a file, or enter monkeyrunner statements in + an interactive session. You do both by invoking the <code>monkeyrunner</code> command + which is found in the <code>tools/</code> subdirectory of your SDK directory. + If you provide a filename as an argument, the <code>monkeyrunner</code> command + runs the file's contents as a Python program; otherwise, it starts an interactive session. +</p> +<p> + The syntax of the <code>monkeyrunner</code> command is +</p> +<pre> +monkeyrunner -plugin <plugin_jar> <program_filename> <program_options> +</pre> +<p> +Table 1 explains the flags and arguments. +</p> +<p class="table-caption" id="table1"> + <strong>Table 1.</strong> <code>monkeyrunner</code> flags and arguments.</p> + +<table> + <tr> + <th>Argument</th> + <th>Description</th> + </tr> + <tr> + <td> + <nobr> + <code>-plugin <plugin_jar></code> + </nobr> + </td> + <td> + (Optional) Specifies a <code>.jar</code> file containing a plugin for monkeyrunner. + To learn more about monkeyrunner plugins, see + <a href="#Plugins">Extending monkeyrunner with plugins</a>. To specify more than one + file, include the argument multiple times. + </td> + </tr> + <tr> + <td> + <nobr> + <code><program_filename></code> + </nobr> + </td> + <td> + If you provide this argument, the <code>monkeyrunner</code> command runs the contents + of the file as a Python program. If the argument is not provided, the command starts an + interactive session. + </td> + </tr> + <tr> + <td> + <code><program_options></code> + </td> + <td> + (Optional) Flags and arguments for the program in <program_file>. + </td> + </tr> +</table> +<h2 id="Help">monkeyrunner Built-in Help</h2> +<p> + You can generate an API reference for monkeyrunner by running: +</p> +<pre> +monkeyrunner <format> help.py <outfile> +</pre> +<p> +The arguments are: +</p> + <ul> + <li> + <code><format></code> is either <code>text</code> for plain text output + or <code>html</code> for HTML output. + </li> + <li> + <code><outfile></code> is a path-qualified name for the output file. + </li> + </ul> +<h2 id="Plugins">Extending monkeyrunner with Plugins</h2> +<p> + You can extend the monkeyrunner API with classes you write in the Java programming language + and build into one or more <code>.jar</code> files. You can use this feature to extend the + monkeyrunner API with your own classes or to extend the existing classes. You can also use this + feature to initialize the monkeyrunner environment. +</p> +<p> + To provide a plugin to monkeyrunner, invoke the <code>monkeyrunner</code> command with the + <code>-plugin <plugin_jar></code> argument described in + <a href="#table1">table 1</a>. +</p> +<p> + In your plugin code, you can import and extend the the main monkeyrunner classes + <code>MonkeyDevice</code>, <code>MonkeyImage</code>, and <code>MonkeyRunner</code> in + <code>com.android.monkeyrunner</code> (see <a href="#APIClasses">The monkeyrunner API</a>). +</p> +<p> + Note that plugins do not give you access to the Android SDK. You can't import packages + such as <code>com.android.app</code>. This is because monkeyrunner interacts with the + device or emulator below the level of the framework APIs. +</p> +<h3>The plugin startup class</h3> +<p> + The <code>.jar</code> file for a plugin can specify a class that is instantiated before + script processing starts. To specify this class, add the key + <code>MonkeyRunnerStartupRunner</code> to the <code>.jar</code> file's + manifest. The value should be the name of the class to run at startup. The following + snippet shows how you would do this within an <code>ant</code> build script: +</p> +<pre> +<jar jarfile="myplugin" basedir="${build.dir}"> +<manifest> +<attribute name="MonkeyRunnerStartupRunner" value="com.myapp.myplugin"/> +</manifest> +</jar> + + +</pre> +<p> + To get access to monkeyrunner's runtime environment, the startup class can implement + <code>com.google.common.base.Predicate<PythonInterpreter></code>. For example, this + class sets up some variables in the default namespace: +</p> +<pre> +package com.android.example; + +import com.google.common.base.Predicate; +import org.python.util.PythonInterpreter; + +public class Main implements Predicate<PythonInterpreter> { + @Override + public boolean apply(PythonInterpreter anInterpreter) { + + /* + * Examples of creating and initializing variables in the monkeyrunner environment's + * namespace. During execution, the monkeyrunner program can refer to the variables "newtest" + * and "use_emulator" + * + */ + anInterpreter.set("newtest", "enabled"); + anInterpreter.set("use_emulator", 1); + + return true; + } +} +</pre> diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 2b80342..a43e334 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -254,34 +254,45 @@ <li><a href="<?cs var:toroot?>guide/topics/search/searchable-config.html">Searchable Configuration</a></li> </ul> </li> + <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html"> + <span class="en">Device Administration</span> + </a> <span class="new">new!</span> + </li> <li class="toggle-list"> <div> - <a href="<?cs var:toroot ?>guide/topics/testing/index.html"> + <a href="<?cs var:toroot?>guide/topics/testing/index.html"> <span class="en">Testing</span> - </a> <span class="new">new!</span> + </a> </div> <ul> - <li><a href="<?cs var:toroot?>guide/topics/testing/testing_android.html"> + <li> + <a href="<?cs var:toroot?>guide/topics/testing/testing_android.html"> <span class="en">Testing Fundamentals</span></a> + <span class="new">new!</span> </li> - <li><a href="<?cs var:toroot?>guide/topics/testing/activity_testing.html"> + <li> + <a href="<?cs var:toroot?>guide/topics/testing/activity_testing.html"> <span class="en">Activity Testing</span></a> + <span class="new">new!</span> </li> - <li><a href="<?cs var:toroot ?>guide/topics/testing/contentprovider_testing.html"> + <li> + <a href="<?cs var:toroot?>guide/topics/testing/contentprovider_testing.html"> <span class="en">Content Provider Testing</span></a> + <span class="new">new!</span> </li> - <li><a href="<?cs var:toroot ?>guide/topics/testing/service_testing.html"> + <li> + <a href="<?cs var:toroot?>guide/topics/testing/service_testing.html"> <span class="en">Service Testing</span></a> + <span class="new">new!</span> </li> - <li><a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html"> + <li> + <a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html"> <span class="en">What To Test</span></a> + <span class="new">new!</span> </li> + </ul> </li> - <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html"> - <span class="en">Device Administration</span> - </a> <span class="new">new!</span> - </li> </ul> </li> @@ -336,6 +347,7 @@ <span class="en">Testing in Eclipse, with ADT</span> </a> </li> + <li> <a href="<?cs var:toroot ?>guide/developing/testing/testing_otheride.html"> <span class="en">Testing in Other IDEs</span> @@ -363,6 +375,34 @@ <li><a href="<?cs var:toroot ?>guide/developing/tools/layoutopt.html">layoutopt</a></li> <li><a href="<?cs var:toroot ?>guide/developing/tools/othertools.html#mksdcard">mksdcard</a></li> <li><a href="<?cs var:toroot ?>guide/developing/tools/monkey.html">Monkey</a></li> + <li class="toggle-list"> + <div> + <a href="<?cs var:toroot?>guide/developing/tools/monkeyrunner_concepts.html"> + <span class="en">monkeyrunner</span> + </a> + <span class="new">new!</span> + </div> + <ul> + <li> + <a href="<?cs var:toroot?>guide/developing/tools/MonkeyDevice.html"> + <span class="en">MonkeyDevice</span> + </a> + <span class="new">new!</span> + </li> + <li> + <a href="<?cs var:toroot?>guide/developing/tools/MonkeyImage.html"> + <span class="en">MonkeyImage</span> + </a> + <span class="new">new!</span> + </li> + <li> + <a href="<?cs var:toroot?>guide/developing/tools/MonkeyRunner.html"> + <span class="en">MonkeyRunner</span> + </a> + <span class="new">new!</span> + </li> + </ul> + </li> <li><a href="<?cs var:toroot ?>guide/developing/tools/adb.html#sqlite">sqlite3</a></li> <li><a href="<?cs var:toroot ?>guide/developing/tools/traceview.html" >Traceview</a></li> <li><a href="<?cs var:toroot ?>guide/developing/tools/zipalign.html" >zipalign</a></li> diff --git a/docs/html/guide/topics/testing/index.jd b/docs/html/guide/topics/testing/index.jd index b75656f..762a897 100644 --- a/docs/html/guide/topics/testing/index.jd +++ b/docs/html/guide/topics/testing/index.jd @@ -59,6 +59,20 @@ page.title=Testing which guides you through a more complex testing scenario. </li> </ul> +<h4>Tools</h4> +<ul> + <li> + The + <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>, + usually called Monkey, is a command-line tool that sends pseudo-random + streams of keystrokes, touches, and gestures to a device. + </li> + <li> + The <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a> tool + is an API and execution environment. You use monkeyrunner with Python programs + to test applications and devices. + </li> +</ul> <h4>Samples</h4> <ul> <li> diff --git a/docs/html/guide/topics/testing/testing_android.jd b/docs/html/guide/topics/testing/testing_android.jd index 2a4c949..d4b0dcc 100755 --- a/docs/html/guide/topics/testing/testing_android.jd +++ b/docs/html/guide/topics/testing/testing_android.jd @@ -38,7 +38,7 @@ page.title=Testing Fundamentals <a href="#TestResults">Seeing Test Results</a> </li> <li> - <a href="#Monkeys">Monkey and MonkeyRunner</a> + <a href="#Monkeys">monkey and monkeyrunner</a> </li> <li> <a href="#PackageNames">Working With Package Names</a> @@ -77,6 +77,13 @@ page.title=Testing Fundamentals <a href="{@docRoot}guide/developing/testing/testing_otheride.html"> Testing in Other IDEs</a> </li> + <li> + <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html"> + monkeyrunner</a> + </li> + <li> + <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a> + </li> </ol> </div> </div> @@ -112,10 +119,10 @@ page.title=Testing Fundamentals </li> <li> The SDK also provides - <a href="{@docRoot}guide/topics/testing/monkeyrunner.html">MonkeyRunner</a>, an API for - testing devices with Jython scripts, and <a - href="{@docRoot}guide/developing/tools/monkey.html">Monkey</a>, a command-line tool for - stress-testing UIs by sending pseudo-random events to a device. + <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a>, an API + testing devices with Python programs, and <a + href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>, + a command-line tool for stress-testing UIs by sending pseudo-random events to a device. </li> </ul> <p> @@ -540,25 +547,28 @@ page.title=Testing Fundamentals <a href="{@docRoot}guide/developing/testing/testing_otheride.html#RunTestsCommand"> Testing in Other IDEs</a>. </p> -<h2 id="Monkeys">Monkey and MonkeyRunner</h2> +<h2 id="Monkeys">monkey and monkeyrunner</h2> <p> The SDK provides two tools for functional-level application testing: </p> <ul> <li> - <a href="{@docRoot}guide/developing/tools/monkey.html">Monkey</a> is a command-line - tool that sends pseudo-random streams of keystrokes, touches, and gestures to a - device. You run it with the <a href="{@docRoot}guide/developing/tools/adb.html"> - Android Debug Bridge</a> (adb) tool. You use it to stress-test your application and - report back errors that are encountered. You can repeat a stream of events by - running the tool each time with the same random number seed. +The <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>, + usually called "monkey", is a command-line tool that sends pseudo-random streams of + keystrokes, touches, and gestures to a device. You run it with the + <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a> (adb) tool. + You use it to stress-test your application and report back errors that are encountered. + You can repeat a stream of events by running the tool each time with the same random + number seed. </li> <li> - <a href="{@docRoot}guide/topics/testing/monkeyrunner.html">MonkeyRunner</a> is a - Jython API that you use in test programs written in Python. The API includes functions - for connecting to a device, installing and uninstalling packages, taking screenshots, - comparing two images, and running a test package against an application. Using the API - with Python, you can write a wide range of large, powerful, and complex tests. + The <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a> tool + is an API and execution environment for test programs written in Python. The API + includes functions for connecting to a device, installing and uninstalling packages, + taking screenshots, comparing two images, and running a test package against an + application. Using the API, you can write a wide range of large, powerful, and complex + tests. You run programs that use the API with the <code>monkeyrunner</code> command-line + tool. </li> </ul> <h2 id="PackageNames">Working With Package names</h2> diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd index 3b4ccb0..cef057e 100644 --- a/docs/html/resources/dashboard/platform-versions.jd +++ b/docs/html/resources/dashboard/platform-versions.jd @@ -52,7 +52,7 @@ Android Market within a 14-day period ending on the data collection date noted b <div class="dashboard-panel"> <img alt="" height="250" width="460" -src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:9.7,16.4,0.1,40.4,33.4&chl= +src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:7.9,15.0,0.1,40.8,36.2&chl= Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b, 6fad0c" /> @@ -62,13 +62,13 @@ Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b, <th>API Level</th> <th>Distribution</th> </tr> -<tr><td>Android 1.5</td><td>3</td><td>9.7%</td></tr> -<tr><td>Android 1.6</td><td>4</td><td>16.4%</td></tr> -<tr><td>Android 2.1</td><td>7</td><td>40.4%</td></tr> -<tr><td>Android 2.2</td><td>8</td><td>33.4%</td></tr> +<tr><td>Android 1.5</td><td>3</td><td>7.9%</td></tr> +<tr><td>Android 1.6</td><td>4</td><td>15.0%</td></tr> +<tr><td>Android 2.1</td><td>7</td><td>40.8%</td></tr> +<tr><td>Android 2.2</td><td>8</td><td>36.2%</td></tr> </table> -<p><em>Data collected during two weeks ending on October 1, 2010</em></p> +<p><em>Data collected during two weeks ending on November 1, 2010</em></p> <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p> </div><!-- end dashboard-panel --> @@ -96,19 +96,18 @@ Android Market within a 14-day period ending on the date indicated on the x-axis <div class="dashboard-panel"> <img alt="" height="250" width="660" style="padding:5px;background:#fff" -src="http://chart.apis.google.com/chart?cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100& -chxl=0:|2010/04/01|04/15|05/01|05/15|06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|2010/10/01|1:|0 -%25|25%25|50%25|75%25|100%25|2:|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12& -chxtc=0,5&chd=t:99.6,99.6,99.6,99.7,100.6,101.1,99.9,100.0,100.0,99.8,99.9,100.0,100.0|61.5,61.7,62. -3,63.5,73.0,76.4,78.6,81.1,84.5,86.6,88.0,89.3,90.3|29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1,68. -2,70.4,72.2,73.9|4.0,28.3,32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8|0.0,0.0,0.0,0.0,0.8 -,1.2,1.8,3.3,4.3,11.3,27.8,32.1,33.4&chm=tAndroid+1.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid+1 -.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|tAndroid+2.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid+2 -.1,2f4708,3,1,15,,t:-30:-40|b,89cf19,3,4,0|tAndroid+2.2,131d02,4,9,15,,t::-5|B,6fad0c,4,5,0&chg=7,25 -&chdl=Android+1.5|Android+1.6|Android+2.0.1|Android+2.1|Android+2.2&chco=add274,9ad145,84c323,6ba213 -,507d08" /> - -<p><em>Last historical dataset collected during two weeks ending on October 1, 2010</em></p> +src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100& +chxl=0%3A%7C2010/05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/ +01%7C10/15%7C2010/11/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25 +%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.9,99.3,100.3,100.8,99.7,99. +8,99.8,99.7,99.8,99.9,99.9,99.9,99.9|61.6,63.1,72.7,76.1,78.4,80.9,84.3,86.5,87.9,89.2,90.2,91.1,92. +0|32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8,75.3,77.0|0.0,0.0,0.8,1.2,1.8,3.3,4.3,11.3, +27.8,32.1,33.4,34.5,36.2&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6, +5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid%202.1,38540b,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid%202. +2,131d02,3,7,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1| +Android%202.2&chco=add274,94d134,73ad18,507d08" /> + +<p><em>Last historical dataset collected during two weeks ending on November 1, 2010</em></p> </div><!-- end dashboard-panel --> diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index f8ad5cc..dfd6ac8 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -199,6 +199,7 @@ public class Allocation extends BaseObj { throw new IllegalStateException("Resize only support for 1D allocations at this time."); } mRS.nAllocationResize1D(mID, dimX); + mRS.finish(); // Necessary because resize is fifoed and update is async. int typeID = mRS.nAllocationGetType(mID); mType = new Type(typeID, mRS); diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index 381b77a..532a2df 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -83,6 +83,11 @@ public class MediaFile { private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U; private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL; + // Drm file types + public static final int FILE_TYPE_FL = 51; + private static final int FIRST_DRM_FILE_TYPE = FILE_TYPE_FL; + private static final int LAST_DRM_FILE_TYPE = FILE_TYPE_FL; + // Other popular file types public static final int FILE_TYPE_TEXT = 100; public static final int FILE_TYPE_HTML = 101; @@ -189,6 +194,8 @@ public class MediaFile { addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST); addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", MtpConstants.FORMAT_WPL_PLAYLIST); + addFileType("FL", FILE_TYPE_FL, "application/x-android-drm-fl"); + addFileType("TXT", FILE_TYPE_TEXT, "text/plain", MtpConstants.FORMAT_TEXT); addFileType("HTM", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML); addFileType("HTML", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML); @@ -222,6 +229,11 @@ public class MediaFile { fileType <= LAST_PLAYLIST_FILE_TYPE); } + public static boolean isDrmFileType(int fileType) { + return (fileType >= FIRST_DRM_FILE_TYPE && + fileType <= LAST_DRM_FILE_TYPE); + } + public static MediaFileType getFileType(String path) { int lastDot = path.lastIndexOf("."); if (lastDot < 0) diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index e5fa0f8..5aabddf 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.IContentProvider; import android.database.Cursor; import android.database.SQLException; +import android.drm.DrmManagerClient; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Process; @@ -360,6 +361,7 @@ public class MediaScanner private ArrayList<FileCacheEntry> mPlayLists; private HashMap<String, Uri> mGenreCache; + private DrmManagerClient mDrmManagerClient = null; public MediaScanner(Context c) { native_setup(); @@ -447,6 +449,11 @@ public class MediaScanner } } + if (System.getProperty("drm.service.enabled").equals("true") + && MediaFile.isDrmFileType(mFileType)) { + mFileType = getFileTypeFromDrm(path); + } + String key = path; if (mCaseInsensitivePaths) { key = path.toLowerCase(); @@ -874,6 +881,27 @@ public class MediaScanner } } + private int getFileTypeFromDrm(String path) { + if (!System.getProperty("drm.service.enabled").equals("true")) { + return 0; + } + + int resultFileType = 0; + + if (mDrmManagerClient == null) { + mDrmManagerClient = new DrmManagerClient(mContext); + } + + if (mDrmManagerClient.canHandle(path, null)) { + String drmMimetype = mDrmManagerClient.getOriginalMimeType(path); + if (drmMimetype != null) { + mMimeType = drmMimetype; + resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype); + } + } + return resultFileType; + } + }; // end of anonymous MediaScannerClient instance private void prescan(String filePath, boolean prescanFiles) throws RemoteException { diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java index 51647434..57ab3a1 100644 --- a/media/java/android/media/MtpDatabase.java +++ b/media/java/android/media/MtpDatabase.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; +import android.os.Environment; import android.os.RemoteException; import android.provider.MediaStore.Audio; import android.provider.MediaStore.Files; @@ -45,6 +46,7 @@ public class MtpDatabase { private final String mVolumeName; private final Uri mObjectsUri; private final String mMediaStoragePath; + private final String mExternalStoragePath; // true if the database has been modified in the current MTP session private boolean mDatabaseModified; @@ -77,7 +79,6 @@ public class MtpDatabase { Files.FileColumns.DATE_MODIFIED, // 5 }; private static final String ID_WHERE = Files.FileColumns._ID + "=?"; - private static final String PATH_WHERE = Files.FileColumns.DATA + "=?"; private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?"; private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + Files.FileColumns.FORMAT + "=?"; @@ -98,6 +99,7 @@ public class MtpDatabase { mMediaProvider = context.getContentResolver().acquireProvider("media"); mVolumeName = volumeName; mMediaStoragePath = storagePath; + mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); mObjectsUri = Files.getMtpObjectsUri(volumeName); mMediaScanner = new MediaScanner(context); openDevicePropertiesDatabase(context); @@ -112,6 +114,16 @@ public class MtpDatabase { } } + private String externalToMediaPath(String path) { + // convert external storage path to media path + if (path != null && mMediaStoragePath != null + && mExternalStoragePath != null + && path.startsWith(mExternalStoragePath)) { + path = mMediaStoragePath + path.substring(mExternalStoragePath.length()); + } + return path; + } + private void openDevicePropertiesDatabase(Context context) { mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null); int version = mDevicePropDb.getVersion(); @@ -482,7 +494,7 @@ public class MtpDatabase { try { c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null); if (c != null && c.moveToNext()) { - path = c.getString(1); + path = externalToMediaPath(c.getString(1)); } } catch (RemoteException e) { Log.e(TAG, "RemoteException in getObjectFilePath", e); @@ -763,7 +775,7 @@ public class MtpDatabase { return true; } } catch (RemoteException e) { - Log.e(TAG, "RemoteException in getObjectProperty", e); + Log.e(TAG, "RemoteException in getObjectInfo", e); } finally { if (c != null) { c.close(); @@ -786,7 +798,7 @@ public class MtpDatabase { c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION, ID_WHERE, new String[] { Integer.toString(handle) }, null); if (c != null && c.moveToNext()) { - String path = c.getString(1); + String path = externalToMediaPath(c.getString(1)); path.getChars(0, path.length(), outFilePath, 0); outFilePath[path.length()] = 0; outFileLength[0] = c.getLong(2); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 0d8abe2..ce48d1c 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -2109,6 +2109,17 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { CODEC_LOGV( "output crop (%ld, %ld, %ld, %ld)", rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight); + + if (mNativeWindow != NULL) { + android_native_rect_t crop; + crop.left = rect.nLeft; + crop.top = rect.nTop; + crop.right = crop.left + rect.nWidth - 1; + crop.bottom = crop.top + rect.nHeight - 1; + + CHECK_EQ(0, native_window_set_crop( + mNativeWindow.get(), &crop)); + } } else { CODEC_LOGE("getConfig(OMX_IndexConfigCommonOutputCrop) " "returned error 0x%08x", err); diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index 1629e9f..6c05e03 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -39,7 +39,7 @@ static bool FileHasAcceptableExtension(const char *extension) { ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2", ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac", ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota", - ".mkv", ".mka", ".webm", ".ts" + ".mkv", ".mka", ".webm", ".ts", ".fl" }; static const size_t kNumValidExtensions = sizeof(kValidExtensions) / sizeof(kValidExtensions[0]); diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index 24fba72..e97b1e6 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -60,6 +60,20 @@ public class Bitmap_Delegate { // ---- Public Helper methods ---- /** + * Returns the native delegate associated to a given {@link Bitmap_Delegate} object. + */ + public static Bitmap_Delegate getDelegate(Bitmap bitmap) { + return sManager.getDelegate(bitmap.mNativeBitmap); + } + + /** + * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object. + */ + public static Bitmap_Delegate getDelegate(int native_bitmap) { + return sManager.getDelegate(native_bitmap); + } + + /** * Creates and returns a {@link Bitmap} initialized with the given file content. */ public static Bitmap createBitmap(File input, Density density) throws IOException { @@ -118,6 +132,13 @@ public class Bitmap_Delegate { return BufferedImage.TYPE_INT_ARGB; } + /** + * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}. + */ + public BufferedImage getImage() { + return mImage; + } + // ---- native methods ---- /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width, @@ -127,8 +148,7 @@ public class Bitmap_Delegate { // create the image BufferedImage image = new BufferedImage(width, height, imageType); - // fill it - //image.setRGB(x, y, rgb) + // FIXME fill the bitmap! // create a delegate with the content of the stream. Bitmap_Delegate delegate = new Bitmap_Delegate(image); diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java deleted file mode 100644 index 24da812..0000000 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java +++ /dev/null @@ -1,1247 +0,0 @@ -/* - * Copyright (C) 2008 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 android.graphics; - -import com.android.layoutlib.api.ILayoutLog; - -import android.graphics.Paint.Align; -import android.graphics.Paint.FontInfo; -import android.graphics.Paint.Style; -import android.graphics.Region.Op; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.util.List; -import java.util.Stack; - -/** - * Re-implementation of the Canvas, 100% in java on top of a BufferedImage. - */ -public class Canvas extends _Original_Canvas { - - private BufferedImage mBufferedImage; - private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>(); - private final ILayoutLog mLogger; - - public Canvas() { - mLogger = null; - // the mBufferedImage will be taken from a bitmap in #setBitmap() - } - - public Canvas(Bitmap bitmap) { - mLogger = null; - mBufferedImage = Bitmap_Delegate.getImage(bitmap); - mGraphicsStack.push(mBufferedImage.createGraphics()); - } - - public Canvas(int nativeCanvas) { - mLogger = null; - throw new UnsupportedOperationException("Can't create Canvas(int)"); - } - - // custom constructors for our use. - public Canvas(int width, int height, ILayoutLog logger) { - mLogger = logger; - mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - mGraphicsStack.push(mBufferedImage.createGraphics()); - } - - public Canvas(int width, int height) { - this(width, height, null /* logger*/); - } - - // custom mehtods - public BufferedImage getImage() { - return mBufferedImage; - } - - public Graphics2D getGraphics2d() { - return mGraphicsStack.peek(); - } - - public void dispose() { - while (mGraphicsStack.size() > 0) { - mGraphicsStack.pop().dispose(); - } - } - - /** - * Creates a new {@link Graphics2D} based on the {@link Paint} parameters. - * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used. - */ - private Graphics2D getCustomGraphics(Paint paint) { - // make new one - Graphics2D g = getGraphics2d(); - g = (Graphics2D)g.create(); - - // configure it - g.setColor(new Color(paint.getColor())); - int alpha = paint.getAlpha(); - float falpha = alpha / 255.f; - - Style style = paint.getStyle(); - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - PathEffect e = paint.getPathEffect(); - if (e instanceof DashPathEffect) { - DashPathEffect dpe = (DashPathEffect)e; - g.setStroke(new BasicStroke( - paint.getStrokeWidth(), - paint.getStrokeCap().getJavaCap(), - paint.getStrokeJoin().getJavaJoin(), - paint.getStrokeMiter(), - dpe.getIntervals(), - dpe.getPhase())); - } else { - g.setStroke(new BasicStroke( - paint.getStrokeWidth(), - paint.getStrokeCap().getJavaCap(), - paint.getStrokeJoin().getJavaJoin(), - paint.getStrokeMiter())); - } - } - - Xfermode xfermode = paint.getXfermode(); - if (xfermode instanceof PorterDuffXfermode) { - PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode(); - - setModeInGraphics(mode, g, falpha); - } else { - if (mLogger != null && xfermode != null) { - mLogger.warning(String.format( - "Xfermode '%1$s' is not supported in the Layout Editor.", - xfermode.getClass().getCanonicalName())); - } - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); - } - - Shader shader = paint.getShader(); - if (shader != null) { - java.awt.Paint shaderPaint = shader.getJavaPaint(); - if (shaderPaint != null) { - g.setPaint(shaderPaint); - } else { - if (mLogger != null) { - mLogger.warning(String.format( - "Shader '%1$s' is not supported in the Layout Editor.", - shader.getClass().getCanonicalName())); - } - } - } - - return g; - } - - private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) { - switch (mode) { - case CLEAR: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha)); - break; - case DARKEN: - break; - case DST: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha)); - break; - case DST_ATOP: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha)); - break; - case DST_IN: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha)); - break; - case DST_OUT: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha)); - break; - case DST_OVER: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha)); - break; - case LIGHTEN: - break; - case MULTIPLY: - break; - case SCREEN: - break; - case SRC: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha)); - break; - case SRC_ATOP: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha)); - break; - case SRC_IN: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha)); - break; - case SRC_OUT: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha)); - break; - case SRC_OVER: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); - break; - case XOR: - g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha)); - break; - } - } - - - // -------------------- - // OVERRIDEN ENUMS - // This is needed since we rename Canvas into _Original_Canvas - // -------------------- - - public enum EdgeType { - BW(0), //!< treat edges by just rounding to nearest pixel boundary - AA(1); //!< treat edges by rounding-out, since they may be antialiased - - EdgeType(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - } - - - // -------------------- - // OVERRIDEN METHODS - // -------------------- - - /* (non-Javadoc) - * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap) - */ - @Override - public void setBitmap(Bitmap bitmap) { - mBufferedImage = Bitmap_Delegate.getImage(bitmap); - mGraphicsStack.push(mBufferedImage.createGraphics()); - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#translate(float, float) - */ - @Override - public void translate(float dx, float dy) { - getGraphics2d().translate(dx, dy); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#save() - */ - @Override - public int save() { - // get the current save count - int count = mGraphicsStack.size(); - - // create a new graphics and add it to the stack - Graphics2D g = (Graphics2D)getGraphics2d().create(); - mGraphicsStack.push(g); - - // return the old save count - return count; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#save(int) - */ - @Override - public int save(int saveFlags) { - // For now we ignore saveFlags - return save(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#restore() - */ - @Override - public void restore() { - mGraphicsStack.pop(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#restoreToCount(int) - */ - @Override - public void restoreToCount(int saveCount) { - while (mGraphicsStack.size() > saveCount) { - mGraphicsStack.pop(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getSaveCount() - */ - @Override - public int getSaveCount() { - return mGraphicsStack.size(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op) - */ - @Override - public boolean clipRect(float left, float top, float right, float bottom, Op op) { - return clipRect(left, top, right, bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(float, float, float, float) - */ - @Override - public boolean clipRect(float left, float top, float right, float bottom) { - getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); - return true; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(int, int, int, int) - */ - @Override - public boolean clipRect(int left, int top, int right, int bottom) { - getGraphics2d().clipRect(left, top, right-left, bottom-top); - return true; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.Rect, android.graphics.Region.Op) - */ - @Override - public boolean clipRect(Rect rect, Op op) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.Rect) - */ - @Override - public boolean clipRect(Rect rect) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.RectF, android.graphics.Region.Op) - */ - @Override - public boolean clipRect(RectF rect, Op op) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRect(android.graphics.RectF) - */ - @Override - public boolean clipRect(RectF rect) { - return clipRect(rect.left, rect.top, rect.right, rect.bottom); - } - - public boolean quickReject(RectF rect, EdgeType type) { - return false; - } - - @Override - public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public boolean quickReject(Path path, EdgeType type) { - return false; - } - - @Override - public boolean quickReject(Path path, _Original_Canvas.EdgeType type) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public boolean quickReject(float left, float top, float right, float bottom, - EdgeType type) { - return false; - } - - @Override - public boolean quickReject(float left, float top, float right, float bottom, - _Original_Canvas.EdgeType type) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - /** - * Retrieve the clip bounds, returning true if they are non-empty. - * - * @param bounds Return the clip bounds here. If it is null, ignore it but - * still return true if the current clip is non-empty. - * @return true if the current clip is non-empty. - */ - @Override - public boolean getClipBounds(Rect bounds) { - Rectangle rect = getGraphics2d().getClipBounds(); - if (rect != null) { - bounds.left = rect.x; - bounds.top = rect.y; - bounds.right = rect.x + rect.width; - bounds.bottom = rect.y + rect.height; - return true; - } - return false; - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode) - */ - @Override - public void drawColor(int color, PorterDuff.Mode mode) { - Graphics2D g = getGraphics2d(); - - // save old color - Color c = g.getColor(); - - Composite composite = g.getComposite(); - - // get the alpha from the color - int alpha = color >>> 24; - float falpha = alpha / 255.f; - - setModeInGraphics(mode, g, falpha); - - g.setColor(new Color(color)); - - g.fillRect(0, 0, getWidth(), getHeight()); - - g.setComposite(composite); - - // restore color - g.setColor(c); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawColor(int) - */ - @Override - public void drawColor(int color) { - drawColor(color, PorterDuff.Mode.SRC_OVER); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawARGB(int, int, int, int) - */ - @Override - public void drawARGB(int a, int r, int g, int b) { - drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRGB(int, int, int) - */ - @Override - public void drawRGB(int r, int g, int b) { - drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER); - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#getWidth() - */ - @Override - public int getWidth() { - return mBufferedImage.getWidth(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getHeight() - */ - @Override - public int getHeight() { - return mBufferedImage.getHeight(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPaint(android.graphics.Paint) - */ - @Override - public void drawPaint(Paint paint) { - drawColor(paint.getColor()); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { - drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - (int)left, (int)top, - (int)left+bitmap.getWidth(), (int)top+bitmap.getHeight(), paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { - boolean needsRestore = false; - if (matrix.isIdentity() == false) { - // create a new graphics and apply the matrix to it - save(); // this creates a new Graphics2D, and stores it for children call to use - needsRestore = true; - Graphics2D g = getGraphics2d(); // get the newly create Graphics2D - - // get the Graphics2D current matrix - AffineTransform currentTx = g.getTransform(); - // get the AffineTransform from the matrix - AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix); - - // combine them so that the matrix is applied after. - currentTx.preConcatenate(matrixTx); - - // give it to the graphics as a new matrix replacing all previous transform - g.setTransform(currentTx); - } - - // draw the bitmap - drawBitmap(bitmap, 0, 0, paint); - - if (needsRestore) { - // remove the new graphics - restore(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { - if (src == null) { - drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - dst.left, dst.top, dst.right, dst.bottom, paint); - } else { - drawBitmap(bitmap, src.left, src.top, src.width(), src.height(), - dst.left, dst.top, dst.right, dst.bottom, paint); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint) - */ - @Override - public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { - if (src == null) { - drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint); - } else { - drawBitmap(bitmap, src.left, src.top, src.width(), src.height(), - (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint) - */ - @Override - public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width, - int height, boolean hasAlpha, Paint paint) { - throw new UnsupportedOperationException(); - } - - private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft, - int dtop, int dright, int dbottom, Paint paint) { - BufferedImage image = Bitmap_Delegate.getImage(bitmap); - - Graphics2D g = getGraphics2d(); - - Composite c = null; - - if (paint != null) { - if (paint.isFilterBitmap()) { - g = (Graphics2D)g.create(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - } - - if (paint.getAlpha() != 0xFF) { - c = g.getComposite(); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - paint.getAlpha()/255.f)); - } - } - - g.drawImage(image, dleft, dtop, dright, dbottom, - sleft, stop, sright, sbottom, null); - - if (paint != null) { - if (paint.isFilterBitmap()) { - g.dispose(); - } - if (c != null) { - g.setComposite(c); - } - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#rotate(float, float, float) - */ - @Override - public void rotate(float degrees, float px, float py) { - if (degrees != 0) { - Graphics2D g = getGraphics2d(); - g.translate(px, py); - g.rotate(Math.toRadians(degrees)); - g.translate(-px, -py); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#rotate(float) - */ - @Override - public void rotate(float degrees) { - getGraphics2d().rotate(Math.toRadians(degrees)); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#scale(float, float, float, float) - */ - @Override - public void scale(float sx, float sy, float px, float py) { - Graphics2D g = getGraphics2d(); - g.translate(px, py); - g.scale(sx, sy); - g.translate(-px, -py); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#scale(float, float) - */ - @Override - public void scale(float sx, float sy) { - getGraphics2d().scale(sx, sy); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint) - */ - @Override - public void drawText(char[] text, int index, int count, float x, float y, Paint paint) { - // WARNING: the logic in this method is similar to Paint.measureText. - // Any change to this method should be reflected in Paint.measureText - Graphics2D g = getGraphics2d(); - - g = (Graphics2D)g.create(); - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - - // set the color. because this only handles RGB, the alpha channel is handled - // as a composite. - g.setColor(new Color(paint.getColor())); - int alpha = paint.getAlpha(); - float falpha = alpha / 255.f; - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); - - - // Paint.TextAlign indicates how the text is positioned relative to X. - // LEFT is the default and there's nothing to do. - if (paint.getTextAlign() != Align.LEFT) { - float m = paint.measureText(text, index, count); - if (paint.getTextAlign() == Align.CENTER) { - x -= m / 2; - } else if (paint.getTextAlign() == Align.RIGHT) { - x -= m; - } - } - - List<FontInfo> fonts = paint.getFonts(); - try { - if (fonts.size() > 0) { - FontInfo mainFont = fonts.get(0); - int i = index; - int lastIndex = index + count; - while (i < lastIndex) { - // always start with the main font. - int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); - if (upTo == -1) { - // draw all the rest and exit. - g.setFont(mainFont.mFont); - g.drawChars(text, i, lastIndex - i, (int)x, (int)y); - return; - } else if (upTo > 0) { - // draw what's possible - g.setFont(mainFont.mFont); - g.drawChars(text, i, upTo - i, (int)x, (int)y); - - // compute the width that was drawn to increase x - x += mainFont.mMetrics.charsWidth(text, i, upTo - i); - - // move index to the first non displayed char. - i = upTo; - - // don't call continue at this point. Since it is certain the main font - // cannot display the font a index upTo (now ==i), we move on to the - // fallback fonts directly. - } - - // no char supported, attempt to read the next char(s) with the - // fallback font. In this case we only test the first character - // and then go back to test with the main font. - // Special test for 2-char characters. - boolean foundFont = false; - for (int f = 1 ; f < fonts.size() ; f++) { - FontInfo fontInfo = fonts.get(f); - - // need to check that the font can display the character. We test - // differently if the char is a high surrogate. - int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; - upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); - if (upTo == -1) { - // draw that char - g.setFont(fontInfo.mFont); - g.drawChars(text, i, charCount, (int)x, (int)y); - - // update x - x += fontInfo.mMetrics.charsWidth(text, i, charCount); - - // update the index in the text, and move on - i += charCount; - foundFont = true; - break; - - } - } - - // in case no font can display the char, display it with the main font. - // (it'll put a square probably) - if (foundFont == false) { - int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; - - g.setFont(mainFont.mFont); - g.drawChars(text, i, charCount, (int)x, (int)y); - - // measure it to advance x - x += mainFont.mMetrics.charsWidth(text, i, charCount); - - // and move to the next chars. - i += charCount; - } - } - } - } finally { - g.dispose(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) - */ - @Override - public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) { - drawText(text.toString().toCharArray(), start, end - start, x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(java.lang.String, float, float, android.graphics.Paint) - */ - @Override - public void drawText(String text, float x, float y, Paint paint) { - drawText(text.toCharArray(), 0, text.length(), x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawText(java.lang.String, int, int, float, float, android.graphics.Paint) - */ - @Override - public void drawText(String text, int start, int end, float x, float y, Paint paint) { - drawText(text.toCharArray(), start, end - start, x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint) - */ - @Override - public void drawRect(RectF rect, Paint paint) { - doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint) - */ - @Override - public void drawRect(float left, float top, float right, float bottom, Paint paint) { - doDrawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top), paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRect(android.graphics.Rect, android.graphics.Paint) - */ - @Override - public void drawRect(Rect r, Paint paint) { - doDrawRect(r.left, r.top, r.width(), r.height(), paint); - } - - private final void doDrawRect(int left, int top, int width, int height, Paint paint) { - if (width > 0 && height > 0) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillRect(left, top, width, height); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawRect(left, top, width, height); - } - - // dispose Graphics2D object - g.dispose(); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint) - */ - @Override - public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { - if (rect.width() > 0 && rect.height() > 0) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - - int arcWidth = (int)(rx * 2); - int arcHeight = (int)(ry * 2); - - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), - arcWidth, arcHeight); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), - arcWidth, arcHeight); - } - - // dispose Graphics2D object - g.dispose(); - } - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawLine(float, float, float, float, android.graphics.Paint) - */ - @Override - public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint) - */ - @Override - public void drawLines(float[] pts, int offset, int count, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - for (int i = 0 ; i < count ; i += 4) { - g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1], - (int)pts[i + offset + 2], (int)pts[i + offset + 3]); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawLines(float[], android.graphics.Paint) - */ - @Override - public void drawLines(float[] pts, Paint paint) { - drawLines(pts, 0, pts.length, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint) - */ - @Override - public void drawCircle(float cx, float cy, float radius, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - int size = (int)(radius * 2); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillOval((int)(cx - radius), (int)(cy - radius), size, size); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawOval((int)(cx - radius), (int)(cy - radius), size, size); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawOval(android.graphics.RectF, android.graphics.Paint) - */ - @Override - public void drawOval(RectF oval, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height()); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height()); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint) - */ - @Override - public void drawPath(Path path, Paint paint) { - // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = getCustomGraphics(paint); - - Style style = paint.getStyle(); - - // draw - if (style == Style.FILL || style == Style.FILL_AND_STROKE) { - g.fill(path.getAwtShape()); - } - - if (style == Style.STROKE || style == Style.FILL_AND_STROKE) { - g.draw(path.getAwtShape()); - } - - // dispose Graphics2D object - g.dispose(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix) - */ - @Override - public void setMatrix(Matrix matrix) { - // get the new current graphics - Graphics2D g = getGraphics2d(); - - // and apply the matrix - g.setTransform(Matrix_Delegate.getAffineTransform(matrix)); - - if (mLogger != null && Matrix_Delegate.hasPerspective(matrix)) { - mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor."); - } - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#concat(android.graphics.Matrix) - */ - @Override - public void concat(Matrix matrix) { - // get the current top graphics2D object. - Graphics2D g = getGraphics2d(); - - // get its current matrix - AffineTransform currentTx = g.getTransform(); - // get the AffineTransform of the given matrix - AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix); - - // combine them so that the given matrix is applied after. - currentTx.preConcatenate(matrixTx); - - // give it to the graphics2D as a new matrix replacing all previous transform - g.setTransform(currentTx); - } - - - // -------------------- - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipPath(android.graphics.Path, android.graphics.Region.Op) - */ - @Override - public boolean clipPath(Path path, Op op) { - // TODO Auto-generated method stub - return super.clipPath(path, op); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipPath(android.graphics.Path) - */ - @Override - public boolean clipPath(Path path) { - // TODO Auto-generated method stub - return super.clipPath(path); - } - - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRegion(android.graphics.Region, android.graphics.Region.Op) - */ - @Override - public boolean clipRegion(Region region, Op op) { - // TODO Auto-generated method stub - return super.clipRegion(region, op); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#clipRegion(android.graphics.Region) - */ - @Override - public boolean clipRegion(Region region) { - // TODO Auto-generated method stub - return super.clipRegion(region); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint) - */ - @Override - public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, - Paint paint) { - // TODO Auto-generated method stub - super.drawArc(oval, startAngle, sweepAngle, useCenter, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint) - */ - @Override - public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, - int vertOffset, int[] colors, int colorOffset, Paint paint) { - // TODO Auto-generated method stub - super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.Rect) - */ - @Override - public void drawPicture(Picture picture, Rect dst) { - // TODO Auto-generated method stub - super.drawPicture(picture, dst); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.RectF) - */ - @Override - public void drawPicture(Picture picture, RectF dst) { - // TODO Auto-generated method stub - super.drawPicture(picture, dst); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPicture(android.graphics.Picture) - */ - @Override - public void drawPicture(Picture picture) { - // TODO Auto-generated method stub - super.drawPicture(picture); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPoint(float, float, android.graphics.Paint) - */ - @Override - public void drawPoint(float x, float y, Paint paint) { - // TODO Auto-generated method stub - super.drawPoint(x, y, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPoints(float[], int, int, android.graphics.Paint) - */ - @Override - public void drawPoints(float[] pts, int offset, int count, Paint paint) { - // TODO Auto-generated method stub - super.drawPoints(pts, offset, count, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPoints(float[], android.graphics.Paint) - */ - @Override - public void drawPoints(float[] pts, Paint paint) { - // TODO Auto-generated method stub - super.drawPoints(pts, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPosText(char[], int, int, float[], android.graphics.Paint) - */ - @Override - public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) { - // TODO Auto-generated method stub - super.drawPosText(text, index, count, pos, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawPosText(java.lang.String, float[], android.graphics.Paint) - */ - @Override - public void drawPosText(String text, float[] pos, Paint paint) { - // TODO Auto-generated method stub - super.drawPosText(text, pos, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint) - */ - @Override - public void drawTextOnPath(char[] text, int index, int count, Path path, float offset, - float offset2, Paint paint) { - // TODO Auto-generated method stub - super.drawTextOnPath(text, index, count, path, offset, offset2, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint) - */ - @Override - public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) { - // TODO Auto-generated method stub - super.drawTextOnPath(text, path, offset, offset2, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint) - */ - @Override - public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, - float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices, - int indexOffset, int indexCount, Paint paint) { - // TODO Auto-generated method stub - super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset, - indices, indexOffset, indexCount, paint); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getDrawFilter() - */ - @Override - public DrawFilter getDrawFilter() { - // TODO Auto-generated method stub - return super.getDrawFilter(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getMatrix() - */ - @Override - public Matrix getMatrix() { - // TODO Auto-generated method stub - return super.getMatrix(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#getMatrix(android.graphics.Matrix) - */ - @Override - public void getMatrix(Matrix ctm) { - // TODO Auto-generated method stub - super.getMatrix(ctm); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#isOpaque() - */ - @Override - public boolean isOpaque() { - // TODO Auto-generated method stub - return super.isOpaque(); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayer(float, float, float, float, android.graphics.Paint, int) - */ - @Override - public int saveLayer(float left, float top, float right, float bottom, Paint paint, - int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayer(left, top, right, bottom, paint, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayer(android.graphics.RectF, android.graphics.Paint, int) - */ - @Override - public int saveLayer(RectF bounds, Paint paint, int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayer(bounds, paint, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int) - */ - @Override - public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, - int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#saveLayerAlpha(android.graphics.RectF, int, int) - */ - @Override - public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) { - // TODO Auto-generated method stub - return super.saveLayerAlpha(bounds, alpha, saveFlags); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter) - */ - @Override - public void setDrawFilter(DrawFilter filter) { - // TODO Auto-generated method stub - super.setDrawFilter(filter); - } - - /* (non-Javadoc) - * @see android.graphics.Canvas#skew(float, float) - */ - @Override - public void skew(float sx, float sy) { - // TODO Auto-generated method stub - super.skew(sx, sy); - } - - - -} diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java new file mode 100644 index 0000000..6627d37 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -0,0 +1,559 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.api.ILayoutLog; +import com.android.layoutlib.bridge.DelegateManager; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.Stack; + +/** + * Delegate implementing the native methods of android.graphics.Canvas + * + * Through the layoutlib_create tool, the original native methods of Canvas have been replaced + * by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original Canvas class. + * + * @see DelegateManager + * + */ +public class Canvas_Delegate { + + // ---- delegate manager ---- + private static final DelegateManager<Canvas_Delegate> sManager = + new DelegateManager<Canvas_Delegate>(); + + // ---- delegate helper data ---- + + // ---- delegate data ---- + private BufferedImage mBufferedImage; + private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>(); + private ILayoutLog mLogger; + + // ---- Public Helper methods ---- + + /** + * Returns the native delegate associated to a given {@link Canvas} object. + */ + public static Canvas_Delegate getDelegate(Canvas canvas) { + return sManager.getDelegate(canvas.mNativeCanvas); + } + + /** + * Returns the native delegate associated to a given an int referencing a {@link Canvas} object. + */ + public static Canvas_Delegate getDelegate(int native_canvas) { + return sManager.getDelegate(native_canvas); + } + + /** + * Sets the layoutlib logger into the canvas. + * @param logger + */ + public void setLogger(ILayoutLog logger) { + mLogger = logger; + } + + /** + * Returns the current {@link Graphics2D} used to draw. + */ + public Graphics2D getGraphics2d() { + return mGraphicsStack.peek(); + } + + /** + * Disposes of the {@link Graphics2D} stack. + */ + public void dispose() { + + } + + // ---- native methods ---- + + /*package*/ static boolean isOpaque(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getWidth(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getHeight(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void rotate(Canvas thisCanvas, float degrees) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void skew(Canvas thisCanvas, float sx, float sy) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right, + float bottom) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right, + int bottom) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int save(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int save(Canvas thisCanvas, int saveFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void restore(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getSaveCount(Canvas thisCanvas) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count, + Paint paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void drawLines(Canvas thisCanvas, float[] pts, int offset, int count, + Paint paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void freeCaches() { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int initRaster(int nativeBitmapOrZero) { + if (nativeBitmapOrZero > 0) { + // get the Bitmap from the int + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero); + + // create a new Canvas_Delegate with the given bitmap and return its new native int. + Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate.getImage()); + + return sManager.addDelegate(newDelegate); + } else { + // create a new Canvas_Delegate and return its new native int. + Canvas_Delegate newDelegate = new Canvas_Delegate(); + + return sManager.addDelegate(newDelegate); + } + } + + /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) { + // get the delegate from the native int. + Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + assert false; + return; + } + + // get the delegate from the native int. + Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap); + if (bitmapDelegate == null) { + assert false; + return; + } + + canvasDelegate.setBitmap(bitmapDelegate.getImage()); + } + + /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds, + int paint, int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_saveLayer(int nativeCanvas, float l, + float t, float r, float b, + int paint, int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_saveLayerAlpha(int nativeCanvas, + RectF bounds, int alpha, + int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l, + float t, float r, float b, + int alpha, int layerFlags) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_concat(int nCanvas, int nMatrix) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_clipRect(int nCanvas, + float left, float top, + float right, float bottom, + int regionOp) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_clipPath(int nativeCanvas, + int nativePath, + int regionOp) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_clipRegion(int nativeCanvas, + int nativeRegion, + int regionOp) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeSetDrawFilter(int nativeCanvas, + int nativeFilter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_getClipBounds(int nativeCanvas, + Rect bounds) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_getCTM(int canvas, int matrix) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_quickReject(int nativeCanvas, + RectF rect, + int native_edgeType) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_quickReject(int nativeCanvas, + int path, + int native_edgeType) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static boolean native_quickReject(int nativeCanvas, + float left, float top, + float right, float bottom, + int native_edgeType) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, + int b) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, + int g, int b) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawColor(int nativeCanvas, int color) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawColor(int nativeCanvas, int color, + int mode) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPaint(int nativeCanvas, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawLine(int nativeCanvas, float startX, + float startY, float stopX, + float stopY, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRect(int nativeCanvas, RectF rect, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRect(int nativeCanvas, float left, + float top, float right, + float bottom, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawOval(int nativeCanvas, RectF oval, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawCircle(int nativeCanvas, float cx, + float cy, float radius, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawArc(int nativeCanvas, RectF oval, + float startAngle, float sweep, + boolean useCenter, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawRoundRect(int nativeCanvas, + RectF rect, float rx, + float ry, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPath(int nativeCanvas, int path, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, + float left, float top, + int nativePaintOrZero, + int canvasDensity, + int screenDensity, + int bitmapDensity) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap, + Rect src, RectF dst, + int nativePaintOrZero, + int screenDensity, + int bitmapDensity) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap, + Rect src, Rect dst, + int nativePaintOrZero, + int screenDensity, + int bitmapDensity) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors, + int offset, int stride, float x, + float y, int width, int height, + boolean hasAlpha, + int nativePaintOrZero) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap, + int nMatrix, int nPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap, + int meshWidth, int meshHeight, + float[] verts, int vertOffset, + int[] colors, int colorOffset, int nPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n, + float[] verts, int vertOffset, float[] texs, int texOffset, + int[] colors, int colorOffset, short[] indices, + int indexOffset, int indexCount, int nPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_drawText(int nativeCanvas, char[] text, + int index, int count, float x, + float y, int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawText(int nativeCanvas, String text, + int start, int end, float x, + float y, int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_drawTextRun(int nativeCanvas, String text, + int start, int end, int contextStart, int contextEnd, + float x, float y, int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text, + int start, int count, int contextStart, int contextCount, + float x, float y, int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static void native_drawPosText(int nativeCanvas, + char[] text, int index, + int count, float[] pos, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPosText(int nativeCanvas, + String text, float[] pos, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawTextOnPath(int nativeCanvas, + char[] text, int index, + int count, int path, + float hOffset, + float vOffset, int bidiFlags, + int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawTextOnPath(int nativeCanvas, + String text, int path, + float hOffset, + float vOffset, + int flags, int paint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_drawPicture(int nativeCanvas, + int nativePicture) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void finalizer(int nativeCanvas) { + sManager.removeDelegate(nativeCanvas); + } + + // ---- Private delegate/helper methods ---- + + private Canvas_Delegate(BufferedImage image) { + setBitmap(image); + } + + private Canvas_Delegate() { + } + + private void setBitmap(BufferedImage image) { + mBufferedImage = image; + mGraphicsStack.push(mBufferedImage.createGraphics()); + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java deleted file mode 100644 index 2de21c1..0000000 --- a/tools/layoutlib/bridge/src/android/graphics/Paint.java +++ /dev/null @@ -1,1211 +0,0 @@ -/* - * Copyright (C) 2008 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 android.graphics; - -import android.text.SpannableString; -import android.text.SpannableStringBuilder; -import android.text.SpannedString; -import android.text.TextUtils; - -import java.awt.BasicStroke; -import java.awt.Font; -import java.awt.Toolkit; -import java.awt.font.FontRenderContext; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A paint implementation overridden by the LayoutLib bridge. - */ -public class Paint extends _Original_Paint { - - private int mColor = 0xFFFFFFFF; - private float mStrokeWidth = 1.f; - private float mTextSize = 20; - private float mScaleX = 1; - private float mSkewX = 0; - private Align mAlign = Align.LEFT; - private Style mStyle = Style.FILL; - private float mStrokeMiter = 4.0f; - private Cap mCap = Cap.BUTT; - private Join mJoin = Join.MITER; - private int mFlags = 0; - - /** - * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}. - */ - public static final class FontInfo { - Font mFont; - java.awt.FontMetrics mMetrics; - } - - private List<FontInfo> mFonts; - private final FontRenderContext mFontContext = new FontRenderContext( - new AffineTransform(), true, true); - - public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG; - public static final int FILTER_BITMAP_FLAG = _Original_Paint.FILTER_BITMAP_FLAG; - public static final int DITHER_FLAG = _Original_Paint.DITHER_FLAG; - public static final int UNDERLINE_TEXT_FLAG = _Original_Paint.UNDERLINE_TEXT_FLAG; - public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG; - public static final int FAKE_BOLD_TEXT_FLAG = _Original_Paint.FAKE_BOLD_TEXT_FLAG; - public static final int LINEAR_TEXT_FLAG = _Original_Paint.LINEAR_TEXT_FLAG; - public static final int SUBPIXEL_TEXT_FLAG = _Original_Paint.SUBPIXEL_TEXT_FLAG; - public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG; - - public static class FontMetrics extends _Original_Paint.FontMetrics { - } - - public static class FontMetricsInt extends _Original_Paint.FontMetricsInt { - } - - /** - * The Style specifies if the primitive being drawn is filled, - * stroked, or both (in the same color). The default is FILL. - */ - public enum Style { - /** - * Geometry and text drawn with this style will be filled, ignoring all - * stroke-related settings in the paint. - */ - FILL (0), - /** - * Geometry and text drawn with this style will be stroked, respecting - * the stroke-related fields on the paint. - */ - STROKE (1), - /** - * Geometry and text drawn with this style will be both filled and - * stroked at the same time, respecting the stroke-related fields on - * the paint. - */ - FILL_AND_STROKE (2); - - Style(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - } - - /** - * The Cap specifies the treatment for the beginning and ending of - * stroked lines and paths. The default is BUTT. - */ - public enum Cap { - /** - * The stroke ends with the path, and does not project beyond it. - */ - BUTT (0), - /** - * The stroke projects out as a square, with the center at the end - * of the path. - */ - ROUND (1), - /** - * The stroke projects out as a semicircle, with the center at the - * end of the path. - */ - SQUARE (2); - - private Cap(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - - /** custom for layoutlib */ - public int getJavaCap() { - switch (this) { - case BUTT: - return BasicStroke.CAP_BUTT; - case ROUND: - return BasicStroke.CAP_ROUND; - default: - case SQUARE: - return BasicStroke.CAP_SQUARE; - } - } - } - - /** - * The Join specifies the treatment where lines and curve segments - * join on a stroked path. The default is MITER. - */ - public enum Join { - /** - * The outer edges of a join meet at a sharp angle - */ - MITER (0), - /** - * The outer edges of a join meet in a circular arc. - */ - ROUND (1), - /** - * The outer edges of a join meet with a straight line - */ - BEVEL (2); - - private Join(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - - /** custom for layoutlib */ - public int getJavaJoin() { - switch (this) { - default: - case MITER: - return BasicStroke.JOIN_MITER; - case ROUND: - return BasicStroke.JOIN_ROUND; - case BEVEL: - return BasicStroke.JOIN_BEVEL; - } - } - } - - /** - * Align specifies how drawText aligns its text relative to the - * [x,y] coordinates. The default is LEFT. - */ - public enum Align { - /** - * The text is drawn to the right of the x,y origin - */ - LEFT (0), - /** - * The text is drawn centered horizontally on the x,y origin - */ - CENTER (1), - /** - * The text is drawn to the left of the x,y origin - */ - RIGHT (2); - - private Align(int nativeInt) { - this.nativeInt = nativeInt; - } - final int nativeInt; - } - - public Paint() { - this(0); - } - - /* - * Do not remove or com.android.layoutlib.bridge.TestClassReplacement fails. - */ - @Override - public void finalize() { } - - public Paint(int flags) { - setFlags(flags | DEFAULT_PAINT_FLAGS); - initFont(); - } - - public Paint(Paint paint) { - set(paint); - initFont(); - } - - @Override - public void reset() { - super.reset(); - } - - /** - * Returns the list of {@link Font} objects. The first item is the main font, the rest - * are fall backs for characters not present in the main font. - */ - public List<FontInfo> getFonts() { - return mFonts; - } - - private void initFont() { - mTypeface = Typeface.DEFAULT; - updateFontObject(); - } - - /** - * Update the {@link Font} object from the typeface, text size and scaling - */ - @SuppressWarnings("deprecation") - private void updateFontObject() { - if (mTypeface != null) { - // Get the fonts from the TypeFace object. - List<Font> fonts = Typeface_Delegate.getFonts(mTypeface); - - // create new font objects as well as FontMetrics, based on the current text size - // and skew info. - ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size()); - for (Font font : fonts) { - FontInfo info = new FontInfo(); - info.mFont = font.deriveFont(mTextSize); - if (mScaleX != 1.0 || mSkewX != 0) { - // TODO: support skew - info.mFont = info.mFont.deriveFont(new AffineTransform( - mScaleX, mSkewX, 0, 0, 1, 0)); - } - info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); - - infoList.add(info); - } - - mFonts = Collections.unmodifiableList(infoList); - } - } - - //---------------------------------------- - - public void set(Paint src) { - if (this != src) { - mColor = src.mColor; - mTextSize = src.mTextSize; - mScaleX = src.mScaleX; - mSkewX = src.mSkewX; - mAlign = src.mAlign; - mStyle = src.mStyle; - mFlags = src.mFlags; - - updateFontObject(); - - super.set(src); - } - } - - @Override - public void setCompatibilityScaling(float factor) { - super.setCompatibilityScaling(factor); - } - - @Override - public int getFlags() { - return mFlags; - } - - @Override - public void setFlags(int flags) { - mFlags = flags; - } - - @Override - public boolean isAntiAlias() { - return super.isAntiAlias(); - } - - @Override - public boolean isDither() { - return super.isDither(); - } - - @Override - public boolean isLinearText() { - return super.isLinearText(); - } - - @Override - public boolean isStrikeThruText() { - return super.isStrikeThruText(); - } - - @Override - public boolean isUnderlineText() { - return super.isUnderlineText(); - } - - @Override - public boolean isFakeBoldText() { - return super.isFakeBoldText(); - } - - @Override - public boolean isSubpixelText() { - return super.isSubpixelText(); - } - - @Override - public boolean isFilterBitmap() { - return super.isFilterBitmap(); - } - - /** - * Return the font's recommended interline spacing, given the Paint's - * settings for typeface, textSize, etc. If metrics is not null, return the - * fontmetric values in it. - * - * @param metrics If this object is not null, its fields are filled with - * the appropriate values given the paint's text attributes. - * @return the font's recommended interline spacing. - */ - public float getFontMetrics(FontMetrics metrics) { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - if (metrics != null) { - // Android expects negative ascent so we invert the value from Java. - metrics.top = - javaMetrics.getMaxAscent(); - metrics.ascent = - javaMetrics.getAscent(); - metrics.descent = javaMetrics.getDescent(); - metrics.bottom = javaMetrics.getMaxDescent(); - metrics.leading = javaMetrics.getLeading(); - } - - return javaMetrics.getHeight(); - } - - return 0; - } - - public int getFontMetricsInt(FontMetricsInt metrics) { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - if (metrics != null) { - // Android expects negative ascent so we invert the value from Java. - metrics.top = - javaMetrics.getMaxAscent(); - metrics.ascent = - javaMetrics.getAscent(); - metrics.descent = javaMetrics.getDescent(); - metrics.bottom = javaMetrics.getMaxDescent(); - metrics.leading = javaMetrics.getLeading(); - } - - return javaMetrics.getHeight(); - } - - return 0; - } - - /** - * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics - */ - public FontMetrics getFontMetrics() { - FontMetrics fm = new FontMetrics(); - getFontMetrics(fm); - return fm; - } - - /** - * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt - */ - public FontMetricsInt getFontMetricsInt() { - FontMetricsInt fm = new FontMetricsInt(); - getFontMetricsInt(fm); - return fm; - } - - - - @Override - public float getFontMetrics(_Original_Paint.FontMetrics metrics) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - @Override - public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - @Override - public Typeface setTypeface(Typeface typeface) { - if (typeface != null) { - mTypeface = typeface; - } else { - mTypeface = Typeface.DEFAULT; - } - - updateFontObject(); - - return typeface; - } - - @Override - public Typeface getTypeface() { - return super.getTypeface(); - } - - @Override - public int getColor() { - return mColor; - } - - @Override - public void setColor(int color) { - mColor = color; - } - - @Override - public void setARGB(int a, int r, int g, int b) { - super.setARGB(a, r, g, b); - } - - @Override - public void setAlpha(int alpha) { - mColor = (alpha << 24) | (mColor & 0x00FFFFFF); - } - - @Override - public int getAlpha() { - return mColor >>> 24; - } - - /** - * Set or clear the shader object. - * <p /> - * Pass null to clear any previous shader. - * As a convenience, the parameter passed is also returned. - * - * @param shader May be null. the new shader to be installed in the paint - * @return shader - */ - @Override - public Shader setShader(Shader shader) { - return mShader = shader; - } - - @Override - public Shader getShader() { - return super.getShader(); - } - - /** - * Set or clear the paint's colorfilter, returning the parameter. - * - * @param filter May be null. The new filter to be installed in the paint - * @return filter - */ - @Override - public ColorFilter setColorFilter(ColorFilter filter) { - mColorFilter = filter; - return filter; - } - - @Override - public ColorFilter getColorFilter() { - return super.getColorFilter(); - } - - /** - * Set or clear the xfermode object. - * <p /> - * Pass null to clear any previous xfermode. - * As a convenience, the parameter passed is also returned. - * - * @param xfermode May be null. The xfermode to be installed in the paint - * @return xfermode - */ - @Override - public Xfermode setXfermode(Xfermode xfermode) { - return mXfermode = xfermode; - } - - @Override - public Xfermode getXfermode() { - return super.getXfermode(); - } - - @Override - public Rasterizer setRasterizer(Rasterizer rasterizer) { - mRasterizer = rasterizer; - return rasterizer; - } - - @Override - public Rasterizer getRasterizer() { - return super.getRasterizer(); - } - - @Override - public void setShadowLayer(float radius, float dx, float dy, int color) { - // TODO Auto-generated method stub - } - - @Override - public void clearShadowLayer() { - super.clearShadowLayer(); - } - - public void setTextAlign(Align align) { - mAlign = align; - } - - @Override - public void setTextAlign(android.graphics._Original_Paint.Align align) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public Align getTextAlign() { - return mAlign; - } - - public void setStyle(Style style) { - mStyle = style; - } - - @Override - public void setStyle(android.graphics._Original_Paint.Style style) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public Style getStyle() { - return mStyle; - } - - @Override - public void setDither(boolean dither) { - mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG; - } - - @Override - public void setAntiAlias(boolean aa) { - mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG; - } - - @Override - public void setFakeBoldText(boolean flag) { - mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG; - } - - @Override - public void setLinearText(boolean flag) { - mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG; - } - - @Override - public void setSubpixelText(boolean flag) { - mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG; - } - - @Override - public void setUnderlineText(boolean flag) { - mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG; - } - - @Override - public void setStrikeThruText(boolean flag) { - mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG; - } - - @Override - public void setFilterBitmap(boolean flag) { - mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG; - } - - @Override - public float getStrokeWidth() { - return mStrokeWidth; - } - - @Override - public void setStrokeWidth(float width) { - mStrokeWidth = width; - } - - @Override - public float getStrokeMiter() { - return mStrokeMiter; - } - - @Override - public void setStrokeMiter(float miter) { - mStrokeMiter = miter; - } - - @Override - public void setStrokeCap(android.graphics._Original_Paint.Cap cap) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public void setStrokeCap(Cap cap) { - mCap = cap; - } - - public Cap getStrokeCap() { - return mCap; - } - - @Override - public void setStrokeJoin(android.graphics._Original_Paint.Join join) { - throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); - } - - public void setStrokeJoin(Join join) { - mJoin = join; - } - - public Join getStrokeJoin() { - return mJoin; - } - - @Override - public boolean getFillPath(Path src, Path dst) { - return super.getFillPath(src, dst); - } - - @Override - public PathEffect setPathEffect(PathEffect effect) { - mPathEffect = effect; - return effect; - } - - @Override - public PathEffect getPathEffect() { - return super.getPathEffect(); - } - - @Override - public MaskFilter setMaskFilter(MaskFilter maskfilter) { - mMaskFilter = maskfilter; - return maskfilter; - } - - @Override - public MaskFilter getMaskFilter() { - return super.getMaskFilter(); - } - - /** - * Return the paint's text size. - * - * @return the paint's text size. - */ - @Override - public float getTextSize() { - return mTextSize; - } - - /** - * Set the paint's text size. This value must be > 0 - * - * @param textSize set the paint's text size. - */ - @Override - public void setTextSize(float textSize) { - mTextSize = textSize; - - updateFontObject(); - } - - /** - * Return the paint's horizontal scale factor for text. The default value - * is 1.0. - * - * @return the paint's scale factor in X for drawing/measuring text - */ - @Override - public float getTextScaleX() { - return mScaleX; - } - - /** - * Set the paint's horizontal scale factor for text. The default value - * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will - * stretch the text narrower. - * - * @param scaleX set the paint's scale in X for drawing/measuring text. - */ - @Override - public void setTextScaleX(float scaleX) { - mScaleX = scaleX; - - updateFontObject(); - } - - /** - * Return the paint's horizontal skew factor for text. The default value - * is 0. - * - * @return the paint's skew factor in X for drawing text. - */ - @Override - public float getTextSkewX() { - return mSkewX; - } - - /** - * Set the paint's horizontal skew factor for text. The default value - * is 0. For approximating oblique text, use values around -0.25. - * - * @param skewX set the paint's skew factor in X for drawing text. - */ - @Override - public void setTextSkewX(float skewX) { - mSkewX = skewX; - - updateFontObject(); - } - - @Override - public float getFontSpacing() { - return super.getFontSpacing(); - } - - /** - * Return the distance above (negative) the baseline (ascent) based on the - * current typeface and text size. - * - * @return the distance above (negative) the baseline (ascent) based on the - * current typeface and text size. - */ - @Override - public float ascent() { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - // Android expects negative ascent so we invert the value from Java. - return - javaMetrics.getAscent(); - } - - return 0; - } - - /** - * Return the distance below (positive) the baseline (descent) based on the - * current typeface and text size. - * - * @return the distance below (positive) the baseline (descent) based on - * the current typeface and text size. - */ - @Override - public float descent() { - if (mFonts.size() > 0) { - java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics; - return javaMetrics.getDescent(); - } - - return 0; - } - - /** - * Return the width of the text. - * - * @param text The text to measure - * @param index The index of the first character to start measuring - * @param count THe number of characters to measure, beginning with start - * @return The width of the text - */ - @Override - public float measureText(char[] text, int index, int count) { - // WARNING: the logic in this method is similar to Canvas.drawText. - // Any change to this method should be reflected in Canvas.drawText - if (mFonts.size() > 0) { - FontInfo mainFont = mFonts.get(0); - int i = index; - int lastIndex = index + count; - float total = 0f; - while (i < lastIndex) { - // always start with the main font. - int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); - if (upTo == -1) { - // shortcut to exit - return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i); - } else if (upTo > 0) { - total += mainFont.mMetrics.charsWidth(text, i, upTo - i); - i = upTo; - // don't call continue at this point. Since it is certain the main font - // cannot display the font a index upTo (now ==i), we move on to the - // fallback fonts directly. - } - - // no char supported, attempt to read the next char(s) with the - // fallback font. In this case we only test the first character - // and then go back to test with the main font. - // Special test for 2-char characters. - boolean foundFont = false; - for (int f = 1 ; f < mFonts.size() ; f++) { - FontInfo fontInfo = mFonts.get(f); - - // need to check that the font can display the character. We test - // differently if the char is a high surrogate. - int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; - upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); - if (upTo == -1) { - total += fontInfo.mMetrics.charsWidth(text, i, charCount); - i += charCount; - foundFont = true; - break; - - } - } - - // in case no font can display the char, measure it with the main font. - if (foundFont == false) { - int size = Character.isHighSurrogate(text[i]) ? 2 : 1; - total += mainFont.mMetrics.charsWidth(text, i, size); - i += size; - } - } - } - - return 0; - } - - /** - * Return the width of the text. - * - * @param text The text to measure - * @param start The index of the first character to start measuring - * @param end 1 beyond the index of the last character to measure - * @return The width of the text - */ - @Override - public float measureText(String text, int start, int end) { - return measureText(text.toCharArray(), start, end - start); - } - - /** - * Return the width of the text. - * - * @param text The text to measure - * @return The width of the text - */ - @Override - public float measureText(String text) { - return measureText(text.toCharArray(), 0, text.length()); - } - - /* - * re-implement to call SpannableStringBuilder.measureText with a Paint object - * instead of an _Original_Paint - */ - @Override - public float measureText(CharSequence text, int start, int end) { - if (text instanceof String) { - return measureText((String)text, start, end); - } - if (text instanceof SpannedString || - text instanceof SpannableString) { - return measureText(text.toString(), start, end); - } - if (text instanceof SpannableStringBuilder) { - return ((SpannableStringBuilder)text).measureText(start, end, this); - } - - char[] buf = TemporaryBuffer.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - float result = measureText(buf, 0, end - start); - TemporaryBuffer.recycle(buf); - return result; - } - - /** - * Measure the text, stopping early if the measured width exceeds maxWidth. - * Return the number of chars that were measured, and if measuredWidth is - * not null, return in it the actual width measured. - * - * @param text The text to measure - * @param index The offset into text to begin measuring at - * @param count The number of maximum number of entries to measure. If count - * is negative, then the characters before index are measured - * in reverse order. This allows for measuring the end of - * string. - * @param maxWidth The maximum width to accumulate. - * @param measuredWidth Optional. If not null, returns the actual width - * measured. - * @return The number of chars that were measured. Will always be <= - * abs(count). - */ - @Override - public int breakText(char[] text, int index, int count, - float maxWidth, float[] measuredWidth) { - int inc = count > 0 ? 1 : -1; - - int measureIndex = 0; - float measureAcc = 0; - for (int i = index ; i != index + count ; i += inc, measureIndex++) { - int start, end; - if (i < index) { - start = i; - end = index; - } else { - start = index; - end = i; - } - - // measure from start to end - float res = measureText(text, start, end - start + 1); - - if (measuredWidth != null) { - measuredWidth[measureIndex] = res; - } - - measureAcc += res; - if (res > maxWidth) { - // we should not return this char index, but since it's 0-based and we need - // to return a count, we simply return measureIndex; - return measureIndex; - } - - } - - return measureIndex; - } - - /** - * Measure the text, stopping early if the measured width exceeds maxWidth. - * Return the number of chars that were measured, and if measuredWidth is - * not null, return in it the actual width measured. - * - * @param text The text to measure - * @param measureForwards If true, measure forwards, starting at index. - * Otherwise, measure backwards, starting with the - * last character in the string. - * @param maxWidth The maximum width to accumulate. - * @param measuredWidth Optional. If not null, returns the actual width - * measured. - * @return The number of chars that were measured. Will always be <= - * abs(count). - */ - @Override - public int breakText(String text, boolean measureForwards, - float maxWidth, float[] measuredWidth) { - return breakText(text, - 0 /* start */, text.length() /* end */, - measureForwards, maxWidth, measuredWidth); - } - - /** - * Measure the text, stopping early if the measured width exceeds maxWidth. - * Return the number of chars that were measured, and if measuredWidth is - * not null, return in it the actual width measured. - * - * @param text The text to measure - * @param start The offset into text to begin measuring at - * @param end The end of the text slice to measure. - * @param measureForwards If true, measure forwards, starting at start. - * Otherwise, measure backwards, starting with end. - * @param maxWidth The maximum width to accumulate. - * @param measuredWidth Optional. If not null, returns the actual width - * measured. - * @return The number of chars that were measured. Will always be <= - * abs(end - start). - */ - @Override - public int breakText(CharSequence text, int start, int end, boolean measureForwards, - float maxWidth, float[] measuredWidth) { - char[] buf = new char[end - start]; - int result; - - TextUtils.getChars(text, start, end, buf, 0); - - if (measureForwards) { - result = breakText(buf, 0, end - start, maxWidth, measuredWidth); - } else { - result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth); - } - - return result; - } - - /** - * Return the advance widths for the characters in the string. - * - * @param text The text to measure - * @param index The index of the first char to to measure - * @param count The number of chars starting with index to measure - * @param widths array to receive the advance widths of the characters. - * Must be at least a large as count. - * @return the actual number of widths returned. - */ - @Override - public int getTextWidths(char[] text, int index, int count, - float[] widths) { - if (mFonts.size() > 0) { - if ((index | count) < 0 || index + count > text.length - || count > widths.length) { - throw new ArrayIndexOutOfBoundsException(); - } - - // FIXME: handle multi-char characters. - // Need to figure out if the lengths of the width array takes into account - // multi-char characters. - for (int i = 0; i < count; i++) { - char c = text[i + index]; - boolean found = false; - for (FontInfo info : mFonts) { - if (info.mFont.canDisplay(c)) { - widths[i] = info.mMetrics.charWidth(c); - found = true; - break; - } - } - - if (found == false) { - // we stop there. - return i; - } - } - - return count; - } - - return 0; - } - - /** - * Return the advance widths for the characters in the string. - * - * @param text The text to measure - * @param start The index of the first char to to measure - * @param end The end of the text slice to measure - * @param widths array to receive the advance widths of the characters. - * Must be at least a large as the text. - * @return the number of unichars in the specified text. - */ - @Override - public int getTextWidths(String text, int start, int end, float[] widths) { - if ((start | end | (end - start) | (text.length() - end)) < 0) { - throw new IndexOutOfBoundsException(); - } - if (end - start > widths.length) { - throw new ArrayIndexOutOfBoundsException(); - } - - return getTextWidths(text.toCharArray(), start, end - start, widths); - } - - /* - * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object - * instead of an _Original_Paint - */ - @Override - public int getTextWidths(CharSequence text, int start, int end, float[] widths) { - if (text instanceof String) { - return getTextWidths((String)text, start, end, widths); - } - if (text instanceof SpannedString || text instanceof SpannableString) { - return getTextWidths(text.toString(), start, end, widths); - } - if (text instanceof SpannableStringBuilder) { - return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this); - } - - char[] buf = TemporaryBuffer.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - int result = getTextWidths(buf, 0, end - start, widths); - TemporaryBuffer.recycle(buf); - return result; - } - - @Override - public int getTextWidths(String text, float[] widths) { - return super.getTextWidths(text, widths); - } - - /** - * Return the path (outline) for the specified text. - * Note: just like Canvas.drawText, this will respect the Align setting in - * the paint. - * - * @param text The text to retrieve the path from - * @param index The index of the first character in text - * @param count The number of characterss starting with index - * @param x The x coordinate of the text's origin - * @param y The y coordinate of the text's origin - * @param path The path to receive the data describing the text. Must - * be allocated by the caller. - */ - @Override - public void getTextPath(char[] text, int index, int count, - float x, float y, Path path) { - - // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE - - if ((index | count) < 0 || index + count > text.length) { - throw new ArrayIndexOutOfBoundsException(); - } - - // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni()); - - throw new UnsupportedOperationException("IMPLEMENT AS NEEDED"); - } - - /** - * Return the path (outline) for the specified text. - * Note: just like Canvas.drawText, this will respect the Align setting - * in the paint. - * - * @param text The text to retrieve the path from - * @param start The first character in the text - * @param end 1 past the last charcter in the text - * @param x The x coordinate of the text's origin - * @param y The y coordinate of the text's origin - * @param path The path to receive the data describing the text. Must - * be allocated by the caller. - */ - @Override - public void getTextPath(String text, int start, int end, - float x, float y, Path path) { - if ((start | end | (end - start) | (text.length() - end)) < 0) { - throw new IndexOutOfBoundsException(); - } - - getTextPath(text.toCharArray(), start, end - start, x, y, path); - } - - /** - * Return in bounds (allocated by the caller) the smallest rectangle that - * encloses all of the characters, with an implied origin at (0,0). - * - * @param text String to measure and return its bounds - * @param start Index of the first char in the string to measure - * @param end 1 past the last char in the string measure - * @param bounds Returns the unioned bounds of all the text. Must be - * allocated by the caller. - */ - @Override - public void getTextBounds(String text, int start, int end, Rect bounds) { - if ((start | end | (end - start) | (text.length() - end)) < 0) { - throw new IndexOutOfBoundsException(); - } - if (bounds == null) { - throw new NullPointerException("need bounds Rect"); - } - - getTextBounds(text.toCharArray(), start, end - start, bounds); - } - - /** - * Return in bounds (allocated by the caller) the smallest rectangle that - * encloses all of the characters, with an implied origin at (0,0). - * - * @param text Array of chars to measure and return their unioned bounds - * @param index Index of the first char in the array to measure - * @param count The number of chars, beginning at index, to measure - * @param bounds Returns the unioned bounds of all the text. Must be - * allocated by the caller. - */ - @Override - public void getTextBounds(char[] text, int index, int count, Rect bounds) { - // FIXME - if (mFonts.size() > 0) { - if ((index | count) < 0 || index + count > text.length) { - throw new ArrayIndexOutOfBoundsException(); - } - if (bounds == null) { - throw new NullPointerException("need bounds Rect"); - } - - FontInfo mainInfo = mFonts.get(0); - - Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext); - bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight()); - } - } - - public static void finalizer(int foo) { - // pass - } -} diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java new file mode 100644 index 0000000..e8079ed --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -0,0 +1,750 @@ +/* + * Copyright (C) 2010 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 android.graphics; + +import com.android.layoutlib.bridge.DelegateManager; + +import android.graphics.Paint.FontMetrics; +import android.graphics.Paint.FontMetricsInt; + +import java.awt.Font; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Delegate implementing the native methods of android.graphics.Paint + * + * Through the layoutlib_create tool, the original native methods of Paint have been replaced + * by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original Paint class. + * + * @see DelegateManager + * + */ +public class Paint_Delegate { + + /** + * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}. + */ + public static final class FontInfo { + Font mFont; + java.awt.FontMetrics mMetrics; + } + + // ---- delegate manager ---- + private static final DelegateManager<Paint_Delegate> sManager = + new DelegateManager<Paint_Delegate>(); + + // ---- delegate helper data ---- + private List<FontInfo> mFonts; + private final FontRenderContext mFontContext = new FontRenderContext( + new AffineTransform(), true, true); + + // ---- delegate data ---- + private int mFlags; + private int mColor; + private int mStyle; + private int mCap; + private int mJoin; + private int mAlign; + private int mTypeface; + private float mStrokeWidth; + private float mStrokeMiter; + private float mTextSize; + private float mTextScaleX; + private float mTextSkewX; + + + // ---- Public Helper methods ---- + + /** + * Returns the list of {@link Font} objects. The first item is the main font, the rest + * are fall backs for characters not present in the main font. + */ + public List<FontInfo> getFonts() { + return mFonts; + } + + + // ---- native methods ---- + + /*package*/ static int getFlags(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mFlags; + } + + /*package*/ static void setFlags(Paint thisPaint, int flags) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mFlags = flags; + } + + /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) { + setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa); + } + + /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) { + setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText); + } + + /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) { + setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText); + } + + /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) { + setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText); + } + + /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) { + setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText); + } + + /*package*/ static void setDither(Paint thisPaint, boolean dither) { + setFlag(thisPaint, Paint.DITHER_FLAG, dither); + } + + /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) { + setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText); + } + + /*package*/ static int getColor(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mColor; + } + + /*package*/ static void setColor(Paint thisPaint, int color) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mColor = color; + } + + /*package*/ static int getAlpha(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mColor >>> 24; + } + + /*package*/ static void setAlpha(Paint thisPaint, int a) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF); + } + + /*package*/ static float getStrokeWidth(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mStrokeWidth; + } + + /*package*/ static void setStrokeWidth(Paint thisPaint, float width) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mStrokeWidth = width; + } + + /*package*/ static float getStrokeMiter(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mStrokeMiter; + } + + /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mStrokeMiter = miter; + } + + /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy, + int color) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float getTextSize(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mTextSize; + } + + /*package*/ static void setTextSize(Paint thisPaint, float textSize) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mTextSize = textSize; + } + + /*package*/ static float getTextScaleX(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mTextScaleX; + } + + /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mTextScaleX = scaleX; + } + + /*package*/ static float getTextSkewX(Paint thisPaint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 1.f; + } + + return delegate.mTextSkewX; + } + + /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + delegate.mTextSkewX = skewX; + } + + /*package*/ static float ascent(Paint thisPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float descent(Paint thisPaint) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index, + int count) { + // WARNING: the logic in this method is similar to Canvas.drawText. + // Any change to this method should be reflected in Canvas.drawText + + // get the delegate + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return 0; + } + + if (delegate.mFonts.size() > 0) { + FontInfo mainFont = delegate.mFonts.get(0); + int i = index; + int lastIndex = index + count; + float total = 0f; + while (i < lastIndex) { + // always start with the main font. + int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex); + if (upTo == -1) { + // shortcut to exit + return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i); + } else if (upTo > 0) { + total += mainFont.mMetrics.charsWidth(text, i, upTo - i); + i = upTo; + // don't call continue at this point. Since it is certain the main font + // cannot display the font a index upTo (now ==i), we move on to the + // fallback fonts directly. + } + + // no char supported, attempt to read the next char(s) with the + // fallback font. In this case we only test the first character + // and then go back to test with the main font. + // Special test for 2-char characters. + boolean foundFont = false; + for (int f = 1 ; f < delegate.mFonts.size() ; f++) { + FontInfo fontInfo = delegate.mFonts.get(f); + + // need to check that the font can display the character. We test + // differently if the char is a high surrogate. + int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1; + upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount); + if (upTo == -1) { + total += fontInfo.mMetrics.charsWidth(text, i, charCount); + i += charCount; + foundFont = true; + break; + + } + } + + // in case no font can display the char, measure it with the main font. + if (foundFont == false) { + int size = Character.isHighSurrogate(text[i]) ? 2 : 1; + total += mainFont.mMetrics.charsWidth(text, i, size); + i += size; + } + } + } + + return 0; + } + + /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) { + return native_measureText(thisPaint, text.toCharArray(), start, end - start); + } + + /*package*/ static float native_measureText(Paint thisPaint, String text) { + return native_measureText(thisPaint, text.toCharArray(), 0, text.length()); + } + + /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count, + float maxWidth, float[] measuredWidth) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards, + float maxWidth, float[] measuredWidth) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static int native_init() { + Paint_Delegate newDelegate = new Paint_Delegate(); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static int native_initWithPaint(int paint) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(paint); + if (delegate == null) { + assert false; + return 0; + } + + Paint_Delegate newDelegate = new Paint_Delegate(delegate); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static void native_reset(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.reset(); + } + + /*package*/ static void native_set(int native_dst, int native_src) { + // get the delegate from the native int. + Paint_Delegate delegate_dst = sManager.getDelegate(native_dst); + if (delegate_dst == null) { + assert false; + return; + } + + // get the delegate from the native int. + Paint_Delegate delegate_src = sManager.getDelegate(native_src); + if (delegate_src == null) { + assert false; + return; + } + + delegate_dst.set(delegate_src); + } + + /*package*/ static int native_getStyle(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mStyle; + } + + /*package*/ static void native_setStyle(int native_object, int style) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mStyle = style; + } + + /*package*/ static int native_getStrokeCap(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mCap; + } + + /*package*/ static void native_setStrokeCap(int native_object, int cap) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mCap = cap; + } + + /*package*/ static int native_getStrokeJoin(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mJoin; + } + + /*package*/ static void native_setStrokeJoin(int native_object, int join) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mJoin = join; + } + + /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setShader(int native_object, int shader) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setColorFilter(int native_object, int filter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setXfermode(int native_object, int xfermode) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setPathEffect(int native_object, int effect) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_setTypeface(int native_object, int typeface) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mTypeface = typeface; + } + + /*package*/ static int native_setRasterizer(int native_object, int rasterizer) { + // FIXME + throw new UnsupportedOperationException(); + } + + + /*package*/ static int native_getTextAlign(int native_object) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return 0; + } + + return delegate.mAlign; + } + + /*package*/ static void native_setTextAlign(int native_object, int align) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(native_object); + if (delegate == null) { + assert false; + return; + } + + delegate.mAlign = align; + } + + /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextWidths(int native_object, char[] text, int index, + int count, float[] widths) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextWidths(int native_object, String text, int start, + int end, float[] widths) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float native_getTextRunAdvances(int native_object, + char[] text, int index, int count, int contextIndex, int contextCount, + int flags, float[] advances, int advancesIndex) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static float native_getTextRunAdvances(int native_object, + String text, int start, int end, int contextStart, int contextEnd, + int flags, float[] advances, int advancesIndex) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text, + int contextStart, int contextLength, int flags, int offset, int cursorOpt) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text, + int contextStart, int contextEnd, int flags, int offset, int cursorOpt) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_getTextPath(int native_object, int bidiFlags, + char[] text, int index, int count, float x, float y, int path) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void native_getTextPath(int native_object, int bidiFlags, + String text, int start, int end, float x, float y, int path) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start, + int end, Rect bounds) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index, + int count, Rect bounds) { + // FIXME + throw new UnsupportedOperationException(); + } + + /*package*/ static void finalizer(int nativePaint) { + sManager.removeDelegate(nativePaint); + } + + // ---- Private delegate/helper methods ---- + + private Paint_Delegate() { + reset(); + + mTypeface = Typeface.sDefaults[0].native_instance; + updateFontObject(); + } + + private Paint_Delegate(Paint_Delegate paint) { + set(paint); + updateFontObject(); + } + + private void set(Paint_Delegate paint) { + mFlags = paint.mFlags; + mColor = paint.mColor; + mStyle = paint.mStyle; + mCap = paint.mCap; + mJoin = paint.mJoin; + mAlign = paint.mAlign; + mTypeface = paint.mTypeface; + mStrokeWidth = paint.mStrokeWidth; + mStrokeMiter = paint.mStrokeMiter; + mTextSize = paint.mTextSize; + mTextScaleX = paint.mTextScaleX; + mTextSkewX = paint.mTextSkewX; + } + + private void reset() { + mFlags = Paint.DEFAULT_PAINT_FLAGS; + mColor = 0; + mStyle = 0; + mCap = 0; + mJoin = 0; + mAlign = 0; + mTypeface = 0; + mStrokeWidth = 1.f; + mStrokeMiter = 2.f; + mTextSize = 20.f; + mTextScaleX = 1.f; + mTextSkewX = 0.f; + } + + /** + * Update the {@link Font} object from the typeface, text size and scaling + */ + private void updateFontObject() { + if (mTypeface != 0) { + // Get the fonts from the TypeFace object. + List<Font> fonts = Typeface_Delegate.getFonts(mTypeface); + + // create new font objects as well as FontMetrics, based on the current text size + // and skew info. + ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size()); + for (Font font : fonts) { + FontInfo info = new FontInfo(); + info.mFont = font.deriveFont(mTextSize); + if (mTextScaleX != 1.0 || mTextSkewX != 0) { + // TODO: support skew + info.mFont = info.mFont.deriveFont(new AffineTransform( + mTextScaleX, mTextSkewX, 0, 0, 1, 0)); + } + info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont); + + infoList.add(info); + } + + mFonts = Collections.unmodifiableList(infoList); + } + } + + private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) { + // get the delegate from the native int. + Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint); + if (delegate == null) { + assert false; + return; + } + + if (flagValue) { + delegate.mFlags |= flagMask; + } else { + delegate.mFlags &= ~flagMask; + } + } +} diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java index 248bdab..7e90e7d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -72,7 +72,11 @@ public final class Typeface_Delegate { } public static List<Font> getFonts(Typeface typeface) { - Typeface_Delegate delegate = sManager.getDelegate(typeface.native_instance); + return getFonts(typeface.native_instance); + } + + public static List<Font> getFonts(int native_int) { + Typeface_Delegate delegate = sManager.getDelegate(native_int); if (delegate == null) { assert false; return null; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 9eb83c8..cdb4148 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -24,6 +24,7 @@ import com.android.layoutlib.api.IProjectCallback; import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.api.IStyleResourceValue; import com.android.layoutlib.api.IXmlPullParser; +import com.android.layoutlib.api.IDensityBasedResourceValue.Density; import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo; import com.android.layoutlib.bridge.LayoutResult.LayoutViewInfo; import com.android.ninepatch.NinePatch; @@ -33,7 +34,9 @@ import com.android.tools.layoutlib.create.OverrideMethod; import android.content.ClipData; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Bitmap_Delegate; import android.graphics.Canvas; +import android.graphics.Canvas_Delegate; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Typeface_Delegate; @@ -64,6 +67,7 @@ import android.widget.FrameLayout; import android.widget.TabHost; import android.widget.TabWidget; +import java.awt.image.BufferedImage; import java.lang.ref.SoftReference; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -450,13 +454,28 @@ public final class Bridge implements ILayoutBridge { view.layout(0, screenOffset, screenWidth, screenHeight); // draw the views - Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger); + // create the BufferedImage into which the layout will be rendered. + BufferedImage image = new BufferedImage(screenWidth, screenHeight - screenOffset, + BufferedImage.TYPE_INT_ARGB); + + // create an Android bitmap around the BufferedImage + Bitmap bitmap = Bitmap_Delegate.createBitmap(image, Density.getEnum(density)); + + // create a Canvas around the Android bitmap + Canvas canvas = new Canvas(bitmap); + + // to set the logger, get the native delegate + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); + canvasDelegate.setLogger(logger); + root.draw(canvas); - canvas.dispose(); + canvasDelegate.dispose(); + + return new LayoutResult( + visit(((ViewGroup)view).getChildAt(0), context), + image); - return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context), - canvas.getImage()); } catch (PostInflateException e) { return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n" + e.getMessage()); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java index abbf2f0..2c92567 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java @@ -19,6 +19,7 @@ package com.android.layoutlib.bridge; import com.android.ninepatch.NinePatch; import android.graphics.Canvas; +import android.graphics.Canvas_Delegate; import android.graphics.ColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -80,7 +81,8 @@ public class NinePatchDrawable extends Drawable { @Override public void draw(Canvas canvas) { Rect r = getBounds(); - m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height()); + Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas); + m9Patch.draw(canvasDelegate.getGraphics2d(), r.left, r.top, r.width(), r.height()); return; } diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java index 6e14e82..ba3c51a 100644 --- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java +++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java @@ -17,8 +17,6 @@ package com.android.layoutlib.bridge; import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics._Original_Paint; import android.text.TextPaint; import junit.framework.TestCase; @@ -58,14 +56,6 @@ public class AndroidGraphicsTests extends TestCase { } } - public void testPaint() { - _Original_Paint o = new _Original_Paint(); - assertNotNull(o); - - Paint p = new Paint(); - assertNotNull(p); - } - public void textTextPaint() { TextPaint p = new TextPaint(); assertNotNull(p); diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java index 7c1eecd..a86b5c9 100644 --- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java +++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java @@ -87,7 +87,11 @@ public class TestNativeDelegate extends TestCase { try { // try to load the method with the given parameter types. - delegateClass.getDeclaredMethod(originalMethod.getName(), parameters); + Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(), + parameters); + + // check that the method is static + assertTrue((delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC); } catch (NoSuchMethodException e) { // compute a full class name that's long but not too long. StringBuilder sb = new StringBuilder(originalMethod.getName() + "("); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 0ecb474..c845cc4 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -104,7 +104,9 @@ public final class CreateInfo implements ICreateInfo { */ private final static String[] DELEGATE_CLASS_NATIVES = new String[] { "android.graphics.Bitmap", + "android.graphics.Canvas", "android.graphics.Matrix", + "android.graphics.Paint", "android.graphics.Typeface", }; @@ -126,11 +128,9 @@ public final class CreateInfo implements ICreateInfo { new String[] { "android.graphics.BitmapFactory", "android.graphics._Original_BitmapFactory", "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader", - "android.graphics.Canvas", "android.graphics._Original_Canvas", "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader", "android.graphics.DashPathEffect", "android.graphics._Original_DashPathEffect", "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient", - "android.graphics.Paint", "android.graphics._Original_Paint", "android.graphics.Path", "android.graphics._Original_Path", "android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode", "android.graphics.RadialGradient", "android.graphics._Original_RadialGradient", @@ -150,13 +150,6 @@ public final class CreateInfo implements ICreateInfo { */ private final static String[] DELETE_RETURNS = new String[] { - "android.graphics.Paint", // class to delete methods from - "android.graphics.Paint$Align", // list of type identifying methods to delete - "android.graphics.Paint$Style", - "android.graphics.Paint$Join", - "android.graphics.Paint$Cap", - "android.graphics.Paint$FontMetrics", - "android.graphics.Paint$FontMetricsInt", null }; // separator, for next class/methods list. } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java index 21d6682..c7968a4 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java @@ -169,7 +169,7 @@ class DelegateMethodAdapter implements MethodVisitor { // Construct the descriptor of the delegate. For a static method, it's the same // however for an instance method we need to pass the 'this' reference first String desc = mDesc; - if (!mIsStatic && argTypes.length > 0) { + if (!mIsStatic) { Type[] argTypes2 = new Type[argTypes.length + 1]; argTypes2[0] = Type.getObjectType(mClassName); |
