diff options
54 files changed, 563 insertions, 213 deletions
diff --git a/api/current.xml b/api/current.xml index 504dab410eee..bf5c8a0c5000 100644 --- a/api/current.xml +++ b/api/current.xml @@ -1949,7 +1949,7 @@ type="int" transient="false" volatile="false" - value="16843554" + value="16843555" static="true" final="true" deprecated="not deprecated" @@ -1960,7 +1960,7 @@ type="int" transient="false" volatile="false" - value="16843553" + value="16843554" static="true" final="true" deprecated="not deprecated" @@ -1971,7 +1971,7 @@ type="int" transient="false" volatile="false" - value="16843555" + value="16843556" static="true" final="true" deprecated="not deprecated" @@ -9396,7 +9396,7 @@ type="int" transient="false" volatile="false" - value="16843557" + value="16843558" static="true" final="true" deprecated="not deprecated" @@ -9407,7 +9407,7 @@ type="int" transient="false" volatile="false" - value="16843556" + value="16843557" static="true" final="true" deprecated="not deprecated" @@ -9898,6 +9898,17 @@ visibility="public" > </field> +<field name="useIntrinsicSizeAsMinimum" + type="int" + transient="false" + volatile="false" + value="16843553" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="useLevel" type="int" transient="false" @@ -246052,7 +246063,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="t" type="T"> +<parameter name="arg0" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 65adef9bbf14..ff769ada47d9 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -375,6 +375,13 @@ public final class Downloads { */ public static final String COLUMN_MEDIA_SCANNED = "scanned"; + /** + * The column with errorMsg for a failed downloaded. + * Used only for debugging purposes. + * <P>Type: TEXT</P> + */ + public static final String COLUMN_ERROR_MSG = "errorMsg"; + /* * Lists the destinations that an application can specify for a download. */ diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index ec8f0310fedb..01a6b94729d5 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -2508,44 +2508,42 @@ public class BluetoothService extends IBluetooth.Stub { // dump pw.println("\n--Headset Service--"); if (mBluetoothHeadset != null) { - List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); - if (deviceList.size() == 0) { - pw.println("\n--No headsets connected--"); - } - BluetoothDevice device = deviceList.get(0); - - switch (mBluetoothHeadset.getConnectionState(device)) { - case BluetoothHeadset.STATE_DISCONNECTED: - pw.println("getConnectionState() = STATE_DISCONNECTED"); - break; - case BluetoothHeadset.STATE_CONNECTING: - pw.println("getConnectionState() = STATE_CONNECTING"); - break; - case BluetoothHeadset.STATE_CONNECTED: - pw.println("getConnectionState() = STATE_CONNECTED"); - break; - case BluetoothHeadset.STATE_DISCONNECTING: - pw.println("getConnectionState() = STATE_DISCONNECTING"); - break; - case BluetoothHeadset.STATE_AUDIO_CONNECTED: - pw.println("getConnectionState() = STATE_AUDIO_CONNECTED"); - break; + List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices(); + if (deviceList.size() == 0) { + pw.println("\n--No headsets connected--"); + } else { + BluetoothDevice device = deviceList.get(0); + pw.println("\ngetConnectedDevices[0] = " + device); + + switch (mBluetoothHeadset.getConnectionState(device)) { + case BluetoothHeadset.STATE_CONNECTING: + pw.println("getConnectionState() = STATE_CONNECTING"); + break; + case BluetoothHeadset.STATE_CONNECTED: + pw.println("getConnectionState() = STATE_CONNECTED"); + break; + case BluetoothHeadset.STATE_DISCONNECTING: + pw.println("getConnectionState() = STATE_DISCONNECTING"); + break; + case BluetoothHeadset.STATE_AUDIO_CONNECTED: + pw.println("getConnectionState() = STATE_AUDIO_CONNECTED"); + break; + } + pw.println("getBatteryUsageHint() = " + + mBluetoothHeadset.getBatteryUsageHint(device)); } deviceList.clear(); deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] { BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED}); pw.println("\n--Connected and Disconnected Headsets"); - for (BluetoothDevice dev: deviceList) { + for (BluetoothDevice device: deviceList) { pw.println(device); if (mBluetoothHeadset.isAudioConnected(device)) { pw.println("SCO audio connected to device:" + device); } } - pw.println("\ngetCurrentHeadset() = " + device); - pw.println("getBatteryUsageHint() = " + - mBluetoothHeadset.getBatteryUsageHint(device)); mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset); } diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index abe33f42a8cd..90c4dd453c2e 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -36,7 +36,7 @@ public: static void finalizer(JNIEnv* env, jobject clazz, SkPath* obj) { #ifdef USE_OPENGL_RENDERER if (android::uirenderer::Caches::hasInstance()) { - android::uirenderer::Caches::getInstance().pathCache.remove(obj); + android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj); } #endif delete obj; diff --git a/core/res/res/drawable-hdpi/progress_bg_holo_dark.9.png b/core/res/res/drawable-hdpi/progress_bg_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..192df6d21f09 --- /dev/null +++ b/core/res/res/drawable-hdpi/progress_bg_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/progress_bg_holo_light.9.png b/core/res/res/drawable-hdpi/progress_bg_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..223416d14272 --- /dev/null +++ b/core/res/res/drawable-hdpi/progress_bg_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/progress_primary_holo_dark.9.png b/core/res/res/drawable-hdpi/progress_primary_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..1a591249fcbc --- /dev/null +++ b/core/res/res/drawable-hdpi/progress_primary_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/progress_primary_holo_light.9.png b/core/res/res/drawable-hdpi/progress_primary_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..f119c6a18709 --- /dev/null +++ b/core/res/res/drawable-hdpi/progress_primary_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/progress_secondary_holo_dark.9.png b/core/res/res/drawable-hdpi/progress_secondary_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..3c6c5eda1d6a --- /dev/null +++ b/core/res/res/drawable-hdpi/progress_secondary_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/progress_secondary_holo_light.9.png b/core/res/res/drawable-hdpi/progress_secondary_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..cab388877999 --- /dev/null +++ b/core/res/res/drawable-hdpi/progress_secondary_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/progress_bg_holo_dark.9.png b/core/res/res/drawable-mdpi/progress_bg_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..316af64f9e24 --- /dev/null +++ b/core/res/res/drawable-mdpi/progress_bg_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/progress_bg_holo_light.9.png b/core/res/res/drawable-mdpi/progress_bg_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..e28613624275 --- /dev/null +++ b/core/res/res/drawable-mdpi/progress_bg_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/progress_primary_holo_dark.9.png b/core/res/res/drawable-mdpi/progress_primary_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..050266964740 --- /dev/null +++ b/core/res/res/drawable-mdpi/progress_primary_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/progress_primary_holo_light.9.png b/core/res/res/drawable-mdpi/progress_primary_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..1ba9e34f2017 --- /dev/null +++ b/core/res/res/drawable-mdpi/progress_primary_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/progress_secondary_holo_dark.9.png b/core/res/res/drawable-mdpi/progress_secondary_holo_dark.9.png Binary files differnew file mode 100644 index 000000000000..a2fe2b302518 --- /dev/null +++ b/core/res/res/drawable-mdpi/progress_secondary_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/progress_secondary_holo_light.9.png b/core/res/res/drawable-mdpi/progress_secondary_holo_light.9.png Binary files differnew file mode 100644 index 000000000000..3b264ab10a2a --- /dev/null +++ b/core/res/res/drawable-mdpi/progress_secondary_holo_light.9.png diff --git a/core/res/res/drawable/progress_horizontal_holo_dark.xml b/core/res/res/drawable/progress_horizontal_holo_dark.xml new file mode 100644 index 000000000000..ff270b3cf7b9 --- /dev/null +++ b/core/res/res/drawable/progress_horizontal_holo_dark.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:id="@android:id/background" + android:drawable="@android:drawable/progress_bg_holo_dark" /> + + <item android:id="@android:id/secondaryProgress"> + <scale android:scaleWidth="100%" + android:drawable="@android:drawable/progress_secondary_holo_dark" /> + </item> + + <item android:id="@android:id/progress"> + <scale android:scaleWidth="100%" + android:drawable="@android:drawable/progress_primary_holo_dark" /> + </item> + +</layer-list> diff --git a/core/res/res/drawable/progress_horizontal_holo_light.xml b/core/res/res/drawable/progress_horizontal_holo_light.xml new file mode 100644 index 000000000000..493518553e67 --- /dev/null +++ b/core/res/res/drawable/progress_horizontal_holo_light.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:id="@android:id/background" + android:drawable="@android:drawable/progress_bg_holo_light" /> + + <item android:id="@android:id/secondaryProgress"> + <scale android:scaleWidth="100%" + android:drawable="@android:drawable/progress_secondary_holo_light" /> + </item> + + <item android:id="@android:id/progress"> + <scale android:scaleWidth="100%" + android:drawable="@android:drawable/progress_primary_holo_light" /> + </item> + +</layer-list> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 5d3dc03d8be7..115e59ddbfb5 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3021,6 +3021,10 @@ </attr> <!-- Reference to a drawable resource to draw with the specified scale. --> <attr name="drawable" /> + <!-- Use the drawable's intrinsic width and height as minimum size values. + Useful if the target drawable is a 9-patch or otherwise should not be scaled + down beyond a minimum size. --> + <attr name="useIntrinsicSizeAsMinimum" format="boolean" /> </declare-styleable> <declare-styleable name="ClipDrawable"> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index ff12e8f60164..a1b9dc90cf27 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1364,6 +1364,7 @@ <public type="attr" name="exitFadeDuration" /> <public type="attr" name="selectableItemBackground" /> <public type="attr" name="autoAdvanceViewId" /> + <public type="attr" name="useIntrinsicSizeAsMinimum" /> <public type="anim" name="animator_fade_in" /> <public type="anim" name="animator_fade_out" /> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index f63805b20b7e..457175b45157 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1359,6 +1359,9 @@ </style> <style name="Widget.Holo.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal"> + <item name="android:progressDrawable">@android:drawable/progress_horizontal_holo_dark</item> + <item name="android:minHeight">16dip</item> + <item name="android:maxHeight">16dip</item> </style> <style name="Widget.Holo.ProgressBar.Small" parent="Widget.ProgressBar.Horizontal"> @@ -1383,8 +1386,8 @@ <item name="android:indeterminateOnly">false</item> <item name="android:progressDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item> <item name="android:indeterminateDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item> - <item name="android:minHeight">16dip</item> - <item name="android:maxHeight">16dip</item> + <item name="android:minHeight">6dip</item> + <item name="android:maxHeight">6dip</item> <item name="android:thumb">@android:drawable/scrubber_control_holo</item> <item name="android:thumbOffset">16dip</item> <item name="android:focusable">true</item> @@ -1646,6 +1649,7 @@ </style> <style name="Widget.Holo.Light.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal"> + <item name="android:progressDrawable">@android:drawable/progress_horizontal_holo_light</item> </style> <style name="Widget.Holo.Light.ProgressBar.Small" parent="Widget.ProgressBar.Small"> diff --git a/docs/html/images/sdk_manager_packages.png b/docs/html/images/sdk_manager_packages.png Binary files differindex 463be8f38749..027cce76c6fe 100755 --- a/docs/html/images/sdk_manager_packages.png +++ b/docs/html/images/sdk_manager_packages.png diff --git a/docs/html/sdk/adding-components.jd b/docs/html/sdk/adding-components.jd index 1f9cb31af13c..d2e55d8e536a 100644 --- a/docs/html/sdk/adding-components.jd +++ b/docs/html/sdk/adding-components.jd @@ -98,20 +98,20 @@ complete.</p> This will reveal all of the components that are currently available for download from the SDK repository.</li> <li>Select the component(s) you'd like to install and click <strong>Install - Selected</strong>. If you aren't sure which packages to select, read <a - href="installing.html#which">Recommended Components</a>.</li> - <li>Verify and accept the components you want and click <strong>Install - Accepted</strong>. The components will now be installed into your existing - Android SDK directories.</li> + Selected</strong>. (If you aren't sure which packages to select, read <a + href="installing.html#which">Recommended Components</a>.)</li> + <li>Verify and accept the components you want (ensure each one is selected with a green +checkmark) and click <strong>Install</strong>. The components will now be installed into +your existing Android SDK directories.</li> </ol> <p>New platforms are automatically saved into the -<code><<em>sdk</em>>/platforms/</code> directory of your SDK; -new add-ons are saved in the <code><<em>sdk</em>>/add-ons/</code> +<code><sdk>/platforms/</code> directory of your SDK; +new add-ons are saved in the <code><sdk>/add-ons/</code> directory; samples are saved in the -<code><<em>sdk</em>>/samples/android-<<em>level</em>>/</code>; +<code><sdk>/samples/android-<level>/</code>; and new documentation is saved in the existing -<code><<em>sdk</em>>/docs/</code> directory (old docs are replaced).</p> +<code><sdk>/docs/</code> directory (old docs are replaced).</p> <h2 id="UpdatingComponents">Updating SDK Components</h2> @@ -167,15 +167,15 @@ components that are needed by those you have selected.</p> <h2 id="AddingSites">Adding New Sites</h2> -<p>By default, <strong>Available Packages</strong> only shows the default -repository site, which offers platforms, SDK tools, documentation, the -Google APIs Add-on, and other components. You can add other sites that host +<p>By default, <strong>Available Packages</strong> displays components available from the +<em>Android Repository</em> and <em>Third party Add-ons</em>. You can add other sites that host their own Android SDK add-ons, then download the SDK add-ons from those sites.</p> <p>For example, a mobile carrier or device manufacturer might offer additional API libraries that are supported by their own Android-powered devices. In order -to develop using their libraries, you must install their Android SDK add-on. </p> +to develop using their libraries, you must install their Android SDK add-on, if it's not already +available under <em>Third party Add-ons</em>. </p> <p>If a carrier or device manufacturer has hosted an SDK add-on repository file on their web site, follow these steps to add their site to the SDK and AVD @@ -183,11 +183,12 @@ Manager:</p> <ol> <li>Select <strong>Available Packages</strong> in the left panel.</li> - <li>Click <strong>Add Site</strong> and enter the URL of the + <li>Click <strong>Add Add-on Site</strong> and enter the URL of the {@code repository.xml} file. Click <strong>OK</strong>.</li> </ol> -<p>Any SDK components available from the site will now be listed under -<strong>Available Packages</strong>.</p> +<p>Any SDK components available from the site will now be listed under a new item named +<strong>User Add-ons</strong>.</p> + <h2 id="troubleshooting">Troubleshooting</h2> diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 3dda5ee9b7ca..8b77303ecf4f 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -23,7 +23,8 @@ sdk.linux_checksum=TODO <ol> <li>Prepare your development computer and ensure it meets the system requirements.</li> - <li>Install the SDK starter package from the table above.</li> + <li>Install the SDK starter package from the table above. (If you're on Windows, download the +installer for help with the initial setup.)</li> <li>Install the ADT Plugin for Eclipse (if you'll be developing in Eclipse).</li> <li>Add Android platforms and other components to your SDK.</li> <li>Explore the contents of the Android SDK (optional).</li> diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd index 2f1918124aaf..4cb1bb22f11d 100644 --- a/docs/html/sdk/installing.jd +++ b/docs/html/sdk/installing.jd @@ -56,6 +56,7 @@ function toggleDiv(link) { <li><a href="#InstallingADT">3. Installing the ADT Plugin for Eclipse</a></li> <li><a href="#components">4. Adding Platforms and Other Components</a> <ol> + <li><a href="#components">Available Components</a></li> <li><a href="#which">Recommended Components</a></li> </ol></li> <li><a href="#sdkContents">5. Exploring the SDK (Optional)</a></li> @@ -119,52 +120,14 @@ href="{@docRoot}sdk/index.html">SDK download page</a>.</p> it to a safe location on your machine. By default, the SDK files are unpacked into a directory named <code>android-sdk-<machine-platform></code>.</p> -<p>Make a note of the name and -location of the unpacked SDK directory on your system—you will need to +<p>If you downloaded the Windows installer ({@code .exe} file), run it now and it will check +whether the proper Java SE Development Kit (JDK) is installed (installing it, if necessary), then +install the SDK Tools into a default location (which you can modify).</p> + +<p>Make a note of the name and location of the SDK directory on your system—you will need to refer to the SDK directory later, when setting up the ADT plugin and when using the SDK tools from command line.</p> -<p>Optionally, you might want to add the location of the SDK's -<code>tools/</code> directory and {@code platform-tools/} directory to your system -<code>PATH</code>. Both tool directories are located at the root of the SDK folder. - - -<div class="toggleable closed"> - <a href="#" onclick="return toggleDiv(this)"> - <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" -width="9px" /> - How to update your PATH</a> - <div class="toggleme"> - -<p>Adding -<code>tools/</code> and {@code platform-tools/} to your path lets you run Android Debug Bridge (adb) -and the other command line <a -href="{@docRoot}guide/developing/tools/index.html">tools</a> without needing to -supply the full path to the tool directories. </p> - -<ul> - <li>On Linux, edit your <code>~/.bash_profile</code> or <code>~/.bashrc</code> file. Look - for a line that sets the PATH environment variable and add the - full path to the <code>tools/</code> and {@code platform-tools/} directories to it. If you don't - see a line setting the path, you can add one: - - <pre>export PATH=${PATH}:<your_sdk_dir>/tools:<your_sdk_dir>/platform-tools</pre> - </li> - - <li>On a Mac OS X, look in your home directory for <code>.bash_profile</code> and - proceed as for Linux. You can create the <code>.bash_profile</code> if - you haven't already set one up on your machine. </li> - - <li>On Windows, right-click on My Computer, and select Properties. - Under the Advanced tab, hit the Environment Variables button, and in the - dialog that comes up, double-click on Path (under System Variables). Add the full path to the - <code>tools/</code> and {@code platform-tools/} directories to the path. </li> - </ul> - -</div><!-- end toggleme --> -</div><!-- end toggleable --> - - <h2 id="InstallingADT">Step 3. Installing the ADT Plugin for Eclipse</h2> @@ -204,28 +167,40 @@ application, you also need to download at least one Android platform and the SDK (tools that the latest platform depend upon). However, downloading additional components is highly recommended.</p> +<p>If you used the Windows installer, when you complete the installation wizard, it will launch the +Android SDK and AVD Manager with a default set of platforms and other components selected +for you to install. Simply click <strong>Install</strong> to accept the recommended set of +components and install them. You can then skip to <a href="#sdkContents">Step 5</a>, but we +recommend you first read the section about the <a href="#components">Available Components</a> to +better understand the components available from the Android SDK and AVD Manager.</p> + <p>You can launch the Android SDK and AVD Manager in one of the following ways:</p> <ul> <li>From within Eclipse, select <strong>Window > Android SDK and AVD Manager</strong>.</li> <li>On Windows, double-click the <code>SDK Manager.ext</code> file at the root of the Android SDK directory.</li> <li>On Mac or Linux, open a terminal and navigate to the <code>tools/</code> directory in the -Android SDK, then execute: <pre>android update sdk</pre> <p>This will automatically select -the required and recommended components for you to install.</p></li> +Android SDK, then execute: <pre>android</pre> </li> </ul> <p>To download components, use the graphical UI of the Android SDK and AVD Manager, shown in Figure 1, to browse the SDK repository and select new or updated components. The Android SDK and AVD Manager will install the selected components in your SDK environment. For information about which components you should download, see the following -section about <a href="#which">Recommended Components</a></p> +section about <a href="#which">Recommended Components</a>.</p> <img src="/images/sdk_manager_packages.png" /> <p class="img-caption"><strong>Figure 1.</strong> The Android SDK and AVD Manager's <strong>Available Packages</strong> panel, which shows the SDK components that are available for you to download into your environment.</p> -<p>The SDK repository offers these types of components:</p> + +<h3 id="components">Available Components</h3> + +<p>By default, there are two repositories of components for your SDK: <em>Android +Repository</em> and <em>Third party Add-ons</em>.</p> + +<p>The <em>Android Repository</em> offers these types of components:</p> <ul> <li><strong>SDK Tools</strong> (pre-installed in the Android SDK starter @@ -249,20 +224,14 @@ system image, sample code, emulator skins, and any version specific tools. For detailed information about each platform, see the overview documents available under the section "Downloadable SDK Components," at left. </li> -<li><strong>SDK Add-Ons</strong> — SDK add-ons provide a development -environment for specific Android external -library or a customized (but fully compliant) Android system image. The Android -SDK repository offers the Google APIs Add-On, which gives your application -access to powerful mapping capabilities through the -<code>com.google.android.maps</code> library. You can also add additional -repositories, so that you can download other SDK add-ons, where available. </li> - -<li><strong>USB Driver for Windows</strong> — Contains driver files +<li><strong>USB Driver for Windows</strong> (Windows only) — Contains driver files that you can install on your Windows computer, so that you can run and debug your applications on an actual device. You <em>do not</em> need the USB driver unless you plan to debug your application on an actual Android-powered device. If you develop on Mac OS X or Linux, you do not need a special driver to debug -your application on an Android-powered device.</li> +your application on an Android-powered device. (See <a +href="{@docRoot}guide/developing/device.html">Developing on a Device</a> for more information +about developing on a real device.)</li> <li><strong>Samples</strong> — Contains the sample code and apps available for each Android development platform. If you are just getting started with @@ -275,6 +244,11 @@ tutorials. --></li> multiversion documentation for the Android framework API. </li> </ul> +<p>The <em>Third party Add-ons</em> provide components that allow you to create a development +environment using a specific Android external library (such as the Google Maps library) or a +customized (but fully compliant) Android system image. You can add additional Add-on repositories, +by clicking <strong>Add Add-on Site</strong>.</p> + <h3 id="which">Recommended Components</h3> @@ -496,6 +470,47 @@ documentation.</td> </table> + +<p>Optionally, you might want to add the location of the SDK's <code>tools/</code> and +<code>platform-tools</code> to your <code>PATH</code> environment variable, to provide easy +access to the tools.</p> + + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" +width="9px" /> + How to update your PATH</a> + <div class="toggleme"> + +<p>Adding both <code>tools/</code> and <code>platform-tools/</code> to your PATH lets you run +command line <a href="{@docRoot}guide/developing/tools/index.html">tools</a> without needing to +supply the full path to the tool directories. Depending on your operating system, you can +include these directories in your PATH in the following way:</p> + +<ul> + + <li>On Windows, right-click on My Computer, and select Properties. + Under the Advanced tab, hit the Environment Variables button, and in the + dialog that comes up, double-click on Path (under System Variables). Add the full path to the + <code>tools/</code> and <code>platform-tools/</code> directories to the path. </li> + + <li>On Linux, edit your <code>~/.bash_profile</code> or <code>~/.bashrc</code> file. Look + for a line that sets the PATH environment variable and add the + full path to the <code>tools/</code> and <code>platform-tools</code> directories to it. If you + don't see a line setting the path, you can add one: + <pre>export PATH=${PATH}:<sdk>/tools:<sdk>/platform-tools</pre> + </li> + + <li>On a Mac OS X, look in your home directory for <code>.bash_profile</code> and + proceed as for Linux. You can create the <code>.bash_profile</code> if + you don't already have one. </li> +</ul> + +</div><!-- end toggleme --> +</div><!-- end toggleable --> + + <h2 id="NextSteps">Next Steps</h2> <p>Once you have completed installation, you are ready to begin developing applications. Here are a few ways you can get started: </p> diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 501cca9ca76f..b6cce7ef5006 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -21,7 +21,10 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.*; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index b623d8002590..dcaf20bc2387 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -95,6 +95,8 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { float sw = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleWidth); float sh = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleHeight); int g = a.getInt(com.android.internal.R.styleable.ScaleDrawable_scaleGravity, Gravity.LEFT); + boolean min = a.getBoolean( + com.android.internal.R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, false); Drawable dr = a.getDrawable(com.android.internal.R.styleable.ScaleDrawable_drawable); a.recycle(); @@ -116,6 +118,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { mScaleState.mScaleWidth = sw; mScaleState.mScaleHeight = sh; mScaleState.mGravity = g; + mScaleState.mUseIntrinsicSizeAsMin = min; if (dr != null) { dr.setCallback(this); } @@ -206,15 +209,16 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { @Override protected void onBoundsChange(Rect bounds) { final Rect r = mTmpRect; + final boolean min = mScaleState.mUseIntrinsicSizeAsMin; int level = getLevel(); int w = bounds.width(); - final int iw = 0; //mScaleState.mDrawable.getIntrinsicWidth(); if (mScaleState.mScaleWidth > 0) { + final int iw = min ? mScaleState.mDrawable.getIntrinsicWidth() : 0; w -= (int) ((w - iw) * (10000 - level) * mScaleState.mScaleWidth / 10000); } int h = bounds.height(); - final int ih = 0; //mScaleState.mDrawable.getIntrinsicHeight(); if (mScaleState.mScaleHeight > 0) { + final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0; h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000); } Gravity.apply(mScaleState.mGravity, w, h, bounds, r); @@ -258,6 +262,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { float mScaleWidth; float mScaleHeight; int mGravity; + boolean mUseIntrinsicSizeAsMin; private boolean mCheckedConstantState; private boolean mCanConstantState; @@ -273,6 +278,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { mScaleWidth = orig.mScaleWidth; mScaleHeight = orig.mScaleHeight; mGravity = orig.mGravity; + mUseIntrinsicSizeAsMin = orig.mUseIntrinsicSizeAsMin; mCheckedConstantState = mCanConstantState = true; } } diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h index d6ae5e9deb97..9d589cf9988a 100644 --- a/include/private/surfaceflinger/SharedBufferStack.h +++ b/include/private/surfaceflinger/SharedBufferStack.h @@ -285,6 +285,8 @@ public: uint32_t getTransform(int buffer) const; status_t resize(int newNumBuffers); + status_t grow(int newNumBuffers); + status_t shrink(int newNumBuffers); SharedBufferStack::Statistics getStats() const; @@ -346,6 +348,14 @@ private: int mNumBuffers; BufferList mBufferList; + struct BuffersAvailableCondition : public ConditionBase { + int mNumBuffers; + inline BuffersAvailableCondition(SharedBufferServer* sbs, + int numBuffers); + inline bool operator()() const; + inline const char* name() const { return "BuffersAvailableCondition"; } + }; + struct UnlockUpdate : public UpdateBase { const int lockedBuffer; inline UnlockUpdate(SharedBufferBase* sbb, int lockedBuffer); diff --git a/keystore/java/android/security/SystemKeyStore.java b/keystore/java/android/security/SystemKeyStore.java index 47718e6c9929..bca8f68ac9f1 100644 --- a/keystore/java/android/security/SystemKeyStore.java +++ b/keystore/java/android/security/SystemKeyStore.java @@ -20,8 +20,6 @@ import android.os.Environment; import android.os.FileUtils; import android.os.Process; -import org.apache.harmony.luni.util.InputStreamHelper; - import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -32,6 +30,8 @@ import java.security.SecureRandom; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import libcore.io.IoUtils; + /** *@hide */ @@ -117,13 +117,10 @@ public class SystemKeyStore { public byte[] retrieveKey(String keyName) throws IOException { File keyFile = getKeyFile(keyName); - if (!keyFile.exists()) { return null; } - - FileInputStream fis = new FileInputStream(keyFile); - return InputStreamHelper.readFullyAndClose(fis); + return IoUtils.readFileAsByteArray(keyFile.toString()); } public void deleteKey(String keyName) { diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 2b498c67265f..40dd11770f3a 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -95,6 +95,16 @@ void Caches::dumpMemoryUsage() { } /////////////////////////////////////////////////////////////////////////////// +// Memory management +/////////////////////////////////////////////////////////////////////////////// + +void Caches::clearGarbage() { + textureCache.clearGarbage(); + gradientCache.clearGarbage(); + pathCache.clearGarbage(); +} + +/////////////////////////////////////////////////////////////////////////////// // VBO /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 2779dfdfed1c..e8ced9c99df1 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -101,6 +101,12 @@ public: } /** + * Call this on each frame to ensure that garbage is deleted from + * GPU memory. + */ + void clearGarbage(); + + /** * Binds the VBO used to render simple textured quads. */ void bindMeshBuffer(); diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index d08df44006be..77d628a4ecd2 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -153,13 +153,13 @@ DisplayList::~DisplayList() { mPaints.clear(); for (size_t i = 0; i < mMatrices.size(); i++) { - delete mMatrices.itemAt(i); + delete mMatrices.itemAt(i); } mMatrices.clear(); if (mPathHeap) { for (int i = 0; i < mPathHeap->count(); i++) { - caches.pathCache.remove(&(*mPathHeap)[i]); + caches.pathCache.removeDeferred(&(*mPathHeap)[i]); } mPathHeap->safeUnref(); } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 97f4cb468c53..a37964eae4cd 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -54,7 +54,6 @@ GradientCache::GradientCache(uint32_t maxByteSize): } GradientCache::~GradientCache() { - Mutex::Autolock _l(mLock); mCache.clear(); } @@ -63,17 +62,14 @@ GradientCache::~GradientCache() { /////////////////////////////////////////////////////////////////////////////// uint32_t GradientCache::getSize() { - Mutex::Autolock _l(mLock); return mSize; } uint32_t GradientCache::getMaxSize() { - Mutex::Autolock _l(mLock); return mMaxSize; } void GradientCache::setMaxSize(uint32_t maxSize) { - Mutex::Autolock _l(mLock); mMaxSize = maxSize; while (mSize > mMaxSize) { mCache.removeOldest(); @@ -102,17 +98,28 @@ void GradientCache::operator()(SkShader*& shader, Texture*& texture) { /////////////////////////////////////////////////////////////////////////////// Texture* GradientCache::get(SkShader* shader) { - Mutex::Autolock _l(mLock); return mCache.get(shader); } void GradientCache::remove(SkShader* shader) { - Mutex::Autolock _l(mLock); mCache.remove(shader); } -void GradientCache::clear() { +void GradientCache::removeDeferred(SkShader* shader) { Mutex::Autolock _l(mLock); + mGarbage.push(shader); +} + +void GradientCache::clearGarbage() { + Mutex::Autolock _l(mLock); + size_t count = mGarbage.size(); + for (size_t i = 0; i < count; i++) { + mCache.remove(mGarbage.itemAt(i)); + } + mGarbage.clear(); +} + +void GradientCache::clear() { mCache.clear(); } @@ -138,21 +145,17 @@ Texture* GradientCache::addLinearGradient(SkShader* shader, uint32_t* colors, canvas.drawRectCoords(0.0f, 0.0f, bitmap.width(), 1.0f, p); - mLock.lock(); // Asume the cache is always big enough const uint32_t size = bitmap.rowBytes() * bitmap.height(); while (mSize + size > mMaxSize) { mCache.removeOldest(); } - mLock.unlock(); Texture* texture = new Texture; generateTexture(&bitmap, texture); - mLock.lock(); mSize += size; mCache.put(shader, texture); - mLock.unlock(); return texture; } diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index c9553f4d6920..30da46209800 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -19,6 +19,8 @@ #include <SkShader.h> +#include <utils/Vector.h> + #include "Texture.h" #include "utils/GenerationCache.h" @@ -53,11 +55,20 @@ public: */ Texture* get(SkShader* shader); /** - * Removes the texture associated with the specified shader. Returns NULL - * if the texture cannot be found. Upon remove the texture is freed. + * Removes the texture associated with the specified shader. + * Upon remove the texture is freed. */ void remove(SkShader* shader); /** + * Removes the texture associated with the specified shader. This is meant + * to be called from threads that are not the EGL context thread. + */ + void removeDeferred(SkShader* shader); + /** + * Process deferred removals. + */ + void clearGarbage(); + /** * Clears the cache. This causes all textures to be deleted. */ void clear(); @@ -83,10 +94,7 @@ private: uint32_t mSize; uint32_t mMaxSize; - /** - * Used to access mCache and mSize. All methods are accessed from a single - * thread except for remove(). - */ + Vector<SkShader*> mGarbage; mutable Mutex mLock; }; // class GradientCache diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index acce1a2155fe..ad7258446509 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -135,6 +135,8 @@ void OpenGLRenderer::setViewport(int width, int height) { } void OpenGLRenderer::prepare(bool opaque) { + mCaches.clearGarbage(); + mSnapshot = new Snapshot(mFirstSnapshot, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); mSaveCount = 1; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 7ff26dcaf080..8740a64601ae 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -53,7 +53,6 @@ PathCache::PathCache(uint32_t maxByteSize): } PathCache::~PathCache() { - Mutex::Autolock _l(mLock); mCache.clear(); } @@ -72,17 +71,14 @@ void PathCache::init() { /////////////////////////////////////////////////////////////////////////////// uint32_t PathCache::getSize() { - Mutex::Autolock _l(mLock); return mSize; } uint32_t PathCache::getMaxSize() { - Mutex::Autolock _l(mLock); return mMaxSize; } void PathCache::setMaxSize(uint32_t maxSize) { - Mutex::Autolock _l(mLock); mMaxSize = maxSize; while (mSize > mMaxSize) { mCache.removeOldest(); @@ -94,6 +90,14 @@ void PathCache::setMaxSize(uint32_t maxSize) { /////////////////////////////////////////////////////////////////////////////// void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) { + removeTexture(texture); +} + +/////////////////////////////////////////////////////////////////////////////// +// Caching +/////////////////////////////////////////////////////////////////////////////// + +void PathCache::removeTexture(PathTexture* texture) { if (texture) { const uint32_t size = texture->width * texture->height; mSize -= size; @@ -109,39 +113,46 @@ void PathCache::operator()(PathCacheEntry& path, PathTexture*& texture) { } } -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - void PathCache::remove(SkPath* path) { - Mutex::Autolock _l(mLock); - // TODO: Linear search... Vector<uint32_t> pathsToRemove; for (uint32_t i = 0; i < mCache.size(); i++) { if (mCache.getKeyAt(i).path == path) { pathsToRemove.push(i); + removeTexture(mCache.getValueAt(i)); } } + mCache.setOnEntryRemovedListener(NULL); for (size_t i = 0; i < pathsToRemove.size(); i++) { mCache.removeAt(pathsToRemove.itemAt(i)); } + mCache.setOnEntryRemovedListener(this); +} + +void PathCache::removeDeferred(SkPath* path) { + Mutex::Autolock _l(mLock); + mGarbage.push(path); +} + +void PathCache::clearGarbage() { + Mutex::Autolock _l(mLock); + size_t count = mGarbage.size(); + for (size_t i = 0; i < count; i++) { + remove(mGarbage.itemAt(i)); + } + mGarbage.clear(); } PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { PathCacheEntry entry(path, paint); - mLock.lock(); PathTexture* texture = mCache.get(entry); - mLock.unlock(); if (!texture) { texture = addTexture(entry, path, paint); } else if (path->getGenerationID() != texture->generation) { - mLock.lock(); mCache.remove(entry); - mLock.unlock(); texture = addTexture(entry, path, paint); } @@ -167,11 +178,9 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry, const uint32_t size = width * height; // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { - mLock.lock(); while (mSize + size > mMaxSize) { mCache.removeOldest(); } - mLock.unlock(); } PathTexture* texture = new PathTexture; @@ -200,7 +209,6 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry, generateTexture(bitmap, texture); if (size < mMaxSize) { - mLock.lock(); mSize += size; PATH_LOGD("PathCache::get: create path: name, size, mSize = %d, %d, %d", texture->id, size, mSize); @@ -208,7 +216,6 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry, LOGD("Path created, size = %d", size); } mCache.put(entry, texture); - mLock.unlock(); } else { texture->cleanup = true; } @@ -217,7 +224,6 @@ PathTexture* PathCache::addTexture(const PathCacheEntry& entry, } void PathCache::clear() { - Mutex::Autolock _l(mLock); mCache.clear(); } diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 0193f43d38e5..ae2e55dfbe2a 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -21,6 +21,8 @@ #include <SkPaint.h> #include <SkPath.h> +#include <utils/Vector.h> + #include "Debug.h" #include "Texture.h" #include "utils/Compare.h" @@ -146,6 +148,15 @@ public: * Removes an entry. */ void remove(SkPath* path); + /** + * Removes the specified path. This is meant to be called from threads + * that are not the EGL context thread. + */ + void removeDeferred(SkPath* path); + /** + * Process deferred removals. + */ + void clearGarbage(); /** * Sets the maximum size of the cache in bytes. @@ -166,6 +177,8 @@ private: */ void generateTexture(SkBitmap& bitmap, Texture* texture); + void removeTexture(PathTexture* texture); + PathTexture* addTexture(const PathCacheEntry& entry, const SkPath *path, const SkPaint* paint); void init(); @@ -178,10 +191,7 @@ private: bool mDebugEnabled; - /** - * Used to access mCache and mSize. All methods are accessed from a single - * thread except for remove(). - */ + Vector<SkPath*> mGarbage; mutable Mutex mLock; }; // class PathCache diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 47c5d489b3e8..5ebd2c0a14ba 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -37,14 +37,17 @@ void ResourceCache::logCache() { } ResourceCache::ResourceCache() { + Mutex::Autolock _l(mLock); mCache = new KeyedVector<void *, ResourceReference *>(); } ResourceCache::~ResourceCache() { + Mutex::Autolock _l(mLock); delete mCache; } void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) { + Mutex::Autolock _l(mLock); for (size_t i = 0; i < mCache->size(); ++i) { void* ref = mCache->valueAt(i); } @@ -73,6 +76,7 @@ void ResourceCache::incrementRefcount(SkiaColorFilter* filterResource) { } void ResourceCache::decrementRefcount(void* resource) { + Mutex::Autolock _l(mLock); ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; if (ref == NULL) { // Should not get here - shouldn't get a call to decrement if we're not yet tracking it @@ -101,6 +105,7 @@ void ResourceCache::decrementRefcount(SkiaColorFilter* filterResource) { } void ResourceCache::recycle(SkBitmap* resource) { + Mutex::Autolock _l(mLock); if (mCache->indexOfKey(resource) < 0) { // not tracking this resource; just recycle the pixel data resource->setPixels(NULL, NULL); @@ -110,6 +115,7 @@ void ResourceCache::recycle(SkBitmap* resource) { } void ResourceCache::recycle(void* resource) { + Mutex::Autolock _l(mLock); ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; if (ref == NULL) { // Should not get here - shouldn't get a call to recycle if we're not yet tracking it @@ -122,11 +128,12 @@ void ResourceCache::recycle(void* resource) { } void ResourceCache::destructor(SkBitmap* resource) { + Mutex::Autolock _l(mLock); ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; if (ref == NULL) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { - Caches::getInstance().textureCache.remove(resource); + Caches::getInstance().textureCache.removeDeferred(resource); } delete resource; return; @@ -139,11 +146,12 @@ void ResourceCache::destructor(SkBitmap* resource) { } void ResourceCache::destructor(SkiaShader* resource) { + Mutex::Autolock _l(mLock); ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; if (ref == NULL) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { - Caches::getInstance().gradientCache.remove(resource->getSkShader()); + Caches::getInstance().gradientCache.removeDeferred(resource->getSkShader()); } delete resource; return; @@ -156,6 +164,7 @@ void ResourceCache::destructor(SkiaShader* resource) { } void ResourceCache::destructor(SkiaColorFilter* resource) { + Mutex::Autolock _l(mLock); ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL; if (ref == NULL) { // If we're not tracking this resource, just delete it @@ -169,6 +178,10 @@ void ResourceCache::destructor(SkiaColorFilter* resource) { } } +/** + * This method should only be called while the mLock mutex is held (that mutex is grabbed + * by the various destructor() and recycle() methods which call this method). + */ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) { if (ref->recycled && ref->resourceType == kBitmap) { ((SkBitmap*) resource)->setPixels(NULL, NULL); @@ -179,7 +192,7 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r { SkBitmap* bitmap = (SkBitmap*)resource; if (Caches::hasInstance()) { - Caches::getInstance().textureCache.remove(bitmap); + Caches::getInstance().textureCache.removeDeferred(bitmap); } delete bitmap; } @@ -188,7 +201,7 @@ void ResourceCache::deleteResourceReference(void* resource, ResourceReference* r { SkiaShader* shader = (SkiaShader*)resource; if (Caches::hasInstance()) { - Caches::getInstance().gradientCache.remove(shader->getSkShader()); + Caches::getInstance().gradientCache.removeDeferred(shader->getSkShader()); } delete shader; } diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h index 2256fd168819..b0abe2c58dcc 100644 --- a/libs/hwui/ResourceCache.h +++ b/libs/hwui/ResourceCache.h @@ -70,6 +70,13 @@ private: void deleteResourceReference(void* resource, ResourceReference* ref); void incrementRefcount(void* resource, ResourceType resourceType); void logCache(); + + /** + * Used to increment, decrement, and destroy. Incrementing is generally accessed on the UI + * thread, but destroying resources may be called from the GC thread, the finalizer thread, + * or a reference queue finalization thread. + */ + mutable Mutex mLock; }; }; // namespace uirenderer diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 1be6868cc051..ebecebec9db7 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -53,7 +53,6 @@ TextureCache::TextureCache(uint32_t maxByteSize): } TextureCache::~TextureCache() { - Mutex::Autolock _l(mLock); mCache.clear(); } @@ -71,17 +70,14 @@ void TextureCache::init() { /////////////////////////////////////////////////////////////////////////////// uint32_t TextureCache::getSize() { - Mutex::Autolock _l(mLock); return mSize; } uint32_t TextureCache::getMaxSize() { - Mutex::Autolock _l(mLock); return mMaxSize; } void TextureCache::setMaxSize(uint32_t maxSize) { - Mutex::Autolock _l(mLock); mMaxSize = maxSize; while (mSize > mMaxSize) { mCache.removeOldest(); @@ -111,9 +107,7 @@ void TextureCache::operator()(SkBitmap*& bitmap, Texture*& texture) { /////////////////////////////////////////////////////////////////////////////// Texture* TextureCache::get(SkBitmap* bitmap) { - mLock.lock(); Texture* texture = mCache.get(bitmap); - mLock.unlock(); if (!texture) { if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) { @@ -124,11 +118,9 @@ Texture* TextureCache::get(SkBitmap* bitmap) { const uint32_t size = bitmap->rowBytes() * bitmap->height(); // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { - mLock.lock(); while (mSize + size > mMaxSize) { mCache.removeOldest(); } - mLock.unlock(); } texture = new Texture; @@ -136,7 +128,6 @@ Texture* TextureCache::get(SkBitmap* bitmap) { generateTexture(bitmap, texture, false); if (size < mMaxSize) { - mLock.lock(); mSize += size; TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d", bitmap, texture->id, size, mSize); @@ -144,7 +135,6 @@ Texture* TextureCache::get(SkBitmap* bitmap) { LOGD("Texture created, size = %d", size); } mCache.put(bitmap, texture); - mLock.unlock(); } else { texture->cleanup = true; } @@ -156,12 +146,24 @@ Texture* TextureCache::get(SkBitmap* bitmap) { } void TextureCache::remove(SkBitmap* bitmap) { - Mutex::Autolock _l(mLock); mCache.remove(bitmap); } -void TextureCache::clear() { +void TextureCache::removeDeferred(SkBitmap* bitmap) { Mutex::Autolock _l(mLock); + mGarbage.push(bitmap); +} + +void TextureCache::clearGarbage() { + Mutex::Autolock _l(mLock); + size_t count = mGarbage.size(); + for (size_t i = 0; i < count; i++) { + mCache.remove(mGarbage.itemAt(i)); + } + mGarbage.clear(); +} + +void TextureCache::clear() { mCache.clear(); TEXTURE_LOGD("TextureCache:clear(), miSize = %d", mSize); } diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 27693df99b0f..f7707f7ae8e8 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -19,6 +19,8 @@ #include <SkBitmap.h> +#include <utils/Vector.h> + #include "Debug.h" #include "Texture.h" #include "utils/GenerationCache.h" @@ -64,11 +66,21 @@ public: */ Texture* get(SkBitmap* bitmap); /** - * Removes the texture associated with the specified bitmap. Returns NULL - * if the texture cannot be found. Upon remove the texture is freed. + * Removes the texture associated with the specified bitmap. + * Upon remove the texture is freed. */ void remove(SkBitmap* bitmap); /** + * Removes the texture associated with the specified bitmap. This is meant + * to be called from threads that are not the EGL context thread. + */ + void removeDeferred(SkBitmap* bitmap); + /** + * Process deferred removals. + */ + void clearGarbage(); + + /** * Clears the cache. This causes all textures to be deleted. */ void clear(); @@ -109,10 +121,7 @@ private: bool mDebugEnabled; - /** - * Used to access mCache and mSize. All methods are accessed from a single - * thread except for remove(). - */ + Vector<SkBitmap*> mGarbage; mutable Mutex mLock; }; // class TextureCache diff --git a/libs/hwui/utils/GenerationCache.h b/libs/hwui/utils/GenerationCache.h index 2e7623602fcc..42e6d9bb8cda 100644 --- a/libs/hwui/utils/GenerationCache.h +++ b/libs/hwui/utils/GenerationCache.h @@ -130,7 +130,7 @@ K GenerationCache<K, V>::getKeyAt(uint32_t index) const { template<typename K, typename V> V GenerationCache<K, V>::getValueAt(uint32_t index) const { - return mCache.valueAt(index); + return mCache.valueAt(index)->value; } template<typename K, typename V> diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index 8f583f06026e..3b2ef848b38f 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -265,6 +265,14 @@ bool SharedBufferClient::LockCondition::operator()() const { (stack.queued > 0 && stack.inUse != buf)); } +SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition( + SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs), + mNumBuffers(numBuffers) { +} +bool SharedBufferServer::BuffersAvailableCondition::operator()() const { + return stack.available == mNumBuffers; +} + // ---------------------------------------------------------------------------- SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb) @@ -448,6 +456,7 @@ status_t SharedBufferClient::queue(int buf) const nsecs_t now = systemTime(SYSTEM_TIME_THREAD); stack.stats.totalTime = ns2us(now - mDequeueTime[buf]); + return err; } @@ -492,6 +501,7 @@ status_t SharedBufferClient::setBufferCount( if (err == NO_ERROR) { mNumBuffers = bufferCount; queued_head = (stack.head + stack.queued) % mNumBuffers; + tail = computeTail(); } return err; } @@ -606,17 +616,24 @@ uint32_t SharedBufferServer::getTransform(int buf) const */ status_t SharedBufferServer::resize(int newNumBuffers) { - if (uint32_t(newNumBuffers) >= SharedBufferStack::NUM_BUFFER_MAX) + if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN || + (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) { return BAD_VALUE; + } RWLock::AutoWLock _l(mLock); - // for now we're not supporting shrinking - const int numBuffers = mNumBuffers; - if (newNumBuffers < numBuffers) - return BAD_VALUE; + if (newNumBuffers < mNumBuffers) { + return shrink(newNumBuffers); + } else { + return grow(newNumBuffers); + } +} +status_t SharedBufferServer::grow(int newNumBuffers) +{ SharedBufferStack& stack( *mSharedStack ); + const int numBuffers = mNumBuffers; const int extra = newNumBuffers - numBuffers; // read the head, make sure it's valid @@ -650,6 +667,54 @@ status_t SharedBufferServer::resize(int newNumBuffers) return NO_ERROR; } +status_t SharedBufferServer::shrink(int newNumBuffers) +{ + SharedBufferStack& stack( *mSharedStack ); + + // Shrinking is only supported if there are no buffers currently dequeued. + int32_t avail = stack.available; + int32_t queued = stack.queued; + if (avail + queued != mNumBuffers) { + return INVALID_OPERATION; + } + + // Wait for any queued buffers to be displayed. + BuffersAvailableCondition condition(this, mNumBuffers); + status_t err = waitForCondition(condition); + if (err < 0) { + return err; + } + + // Reset head to index 0 and make it refer to buffer 0. The same renaming + // (head -> 0) is done in the BufferManager. + int32_t head = stack.head; + int8_t* index = const_cast<int8_t*>(stack.index); + for (int8_t i = 0; i < newNumBuffers; i++) { + index[i] = i; + } + stack.head = 0; + stack.headBuf = 0; + + // If one of the buffers is in use it must be the head buffer, which we are + // renaming to buffer 0. + if (stack.inUse > 0) { + stack.inUse = 0; + } + + // Free the buffers from the end of the list that are no longer needed. + for (int i = newNumBuffers; i < mNumBuffers; i++) { + mBufferList.remove(i); + } + + // Tell the client to reallocate all the buffers. + reallocateAll(); + + mNumBuffers = newNumBuffers; + stack.available = newNumBuffers; + + return NO_ERROR; +} + SharedBufferStack::Statistics SharedBufferServer::getStats() const { SharedBufferStack& stack( *mSharedStack ); diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index c1e00ca68a17..9467a4cf0c08 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -855,6 +855,12 @@ int Surface::setBufferCount(int bufferCount) status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc); LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s", bufferCount, strerror(-err)); + + if (err == NO_ERROR) { + // Clear out any references to the old buffers. + mBuffers.clear(); + } + return err; } diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp index f409f4828970..7ef59269bade 100644 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp +++ b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp @@ -32,7 +32,8 @@ void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); int main(int argc, char** argv) { SharedClient client; - SharedBufferServer s(&client, 0, 4, 0); + sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0)); + SharedBufferServer& s(*ps); SharedBufferClient c(&client, 0, 4, 0); printf("basic test 0\n"); @@ -67,6 +68,10 @@ int main(int argc, char** argv) int list3[6] = {3, 2, 1, 4, 5, 0}; test0(s, c, 6, list3); + c.setBufferCount(4, resize); + int list4[4] = {1, 2, 3, 0}; + test0(s, c, 4, list4); + return 0; } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 4e1969bc437c..f084e283a8e8 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -564,6 +564,12 @@ bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { return false; } +void AwesomePlayer::ensureCacheIsFetching_l() { + if (mCachedSource != NULL) { + mCachedSource->resumeFetchingIfNecessary(); + } +} + void AwesomePlayer::onBufferingUpdate() { Mutex::Autolock autoLock(mLock); if (!mBufferingEventPending) { @@ -606,6 +612,7 @@ void AwesomePlayer::onBufferingUpdate() { kLowWaterMarkBytes); mFlags |= CACHE_UNDERRUN; pause_l(); + ensureCacheIsFetching_l(); notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { if (mFlags & CACHE_UNDERRUN) { @@ -627,12 +634,16 @@ void AwesomePlayer::onBufferingUpdate() { int64_t cachedDurationUs; bool eos; if (getCachedDuration_l(&cachedDurationUs, &eos)) { + LOGV("cachedDurationUs = %.2f secs, eos=%d", + cachedDurationUs / 1E6, eos); + if ((mFlags & PLAYING) && !eos && (cachedDurationUs < kLowWaterMarkUs)) { LOGI("cache is running low (%.2f secs) , pausing.", cachedDurationUs / 1E6); mFlags |= CACHE_UNDERRUN; pause_l(); + ensureCacheIsFetching_l(); notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); } else if (eos || cachedDurationUs > kHighWaterMarkUs) { if (mFlags & CACHE_UNDERRUN) { diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index a69c396944b6..4a2402ba2e81 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -325,15 +325,17 @@ void NuCachedSource2::onRead(const sp<AMessage> &msg) { mCondition.signal(); } -void NuCachedSource2::restartPrefetcherIfNecessary_l() { +void NuCachedSource2::restartPrefetcherIfNecessary_l( + bool ignoreLowWaterThreshold) { static const size_t kGrayArea = 256 * 1024; if (mFetching || mFinalStatus != OK) { return; } - if (mCacheOffset + mCache->totalSize() - mLastAccessPos - >= kLowWaterThreshold) { + if (!ignoreLowWaterThreshold + && mCacheOffset + mCache->totalSize() - mLastAccessPos + >= kLowWaterThreshold) { return; } @@ -510,6 +512,12 @@ void NuCachedSource2::onSuspend() { mSuspended = true; } +void NuCachedSource2::resumeFetchingIfNecessary() { + Mutex::Autolock autoLock(mLock); + + restartPrefetcherIfNecessary_l(true /* ignore low water threshold */); +} + DecryptHandle* NuCachedSource2::DrmInitialization(DrmManagerClient* client) { return mSource->DrmInitialization(client); } diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index a0a743654d50..302a1ba609b2 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -274,6 +274,7 @@ private: bool getBitrate(int64_t *bitrate); void finishSeekIfNecessary(int64_t videoTimeUs); + void ensureCacheIsFetching_l(); AwesomePlayer(const AwesomePlayer &); AwesomePlayer &operator=(const AwesomePlayer &); diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index 406758501c8a..8cec1b1eafaa 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -47,6 +47,8 @@ struct NuCachedSource2 : public DataSource { void suspend(); void clearCacheAndResume(); + void resumeFetchingIfNecessary(); + protected: virtual ~NuCachedSource2(); @@ -56,7 +58,7 @@ private: enum { kPageSize = 65536, kHighWaterThreshold = 5 * 1024 * 1024, - kLowWaterThreshold = 512 * 1024, + kLowWaterThreshold = 1024 * 1024, // Read data after a 15 sec timeout whether we're actively // fetching or not. @@ -96,7 +98,7 @@ private: status_t seekInternal_l(off_t offset); size_t approxDataRemaining_l(bool *eos); - void restartPrefetcherIfNecessary_l(); + void restartPrefetcherIfNecessary_l(bool ignoreLowWaterThreshold = false); DISALLOW_EVIL_CONSTRUCTORS(NuCachedSource2); }; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index c9ab9922482e..b5e73ac5e78f 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -218,25 +218,13 @@ bool SensorService::threadLoop() break; } + recordLastValue(buffer, count); + const SortedVector< wp<SensorEventConnection> > activeConnections( getActiveConnections()); size_t numConnections = activeConnections.size(); if (numConnections) { - Mutex::Autolock _l(mLock); - - // record the last event for each sensor - int32_t prev = buffer[0].sensor; - for (ssize_t i=1 ; i<count ; i++) { - // record the last event of each sensor type in this buffer - int32_t curr = buffer[i].sensor; - if (curr != prev) { - mLastEventSeen.editValueFor(prev) = buffer[i-1]; - prev = curr; - } - } - mLastEventSeen.editValueFor(prev) = buffer[count-1]; - for (size_t i=0 ; i<numConnections ; i++) { sp<SensorEventConnection> connection(activeConnections[i].promote()); if (connection != 0) { @@ -251,6 +239,24 @@ bool SensorService::threadLoop() return false; } +void SensorService::recordLastValue( + sensors_event_t const * buffer, size_t count) +{ + Mutex::Autolock _l(mLock); + + // record the last event for each sensor + int32_t prev = buffer[0].sensor; + for (size_t i=1 ; i<count ; i++) { + // record the last event of each sensor type in this buffer + int32_t curr = buffer[i].sensor; + if (curr != prev) { + mLastEventSeen.editValueFor(prev) = buffer[i-1]; + prev = curr; + } + } + mLastEventSeen.editValueFor(prev) = buffer[count-1]; +} + SortedVector< wp<SensorService::SensorEventConnection> > SensorService::getActiveConnections() const { diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index dfb1c0e15c63..b442779d5ac0 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -111,6 +111,8 @@ class SensorService : String8 getSensorName(int handle) const; status_t recomputeEventsPeriodLocked(int32_t handle); + void recordLastValue(sensors_event_t const * buffer, size_t count); + // constants Vector<Sensor> mSensorList; struct sensors_poll_device_t* mSensorDevice; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1b06843df7ee..7be58c6541ac 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -340,8 +340,10 @@ status_t Layer::setBufferCount(int bufferCount) // NOTE: lcblk->resize() is protected by an internal lock status_t err = lcblk->resize(bufferCount); - if (err == NO_ERROR) - mBufferManager.resize(bufferCount); + if (err == NO_ERROR) { + EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); + mBufferManager.resize(bufferCount, mFlinger, dpy); + } return err; } @@ -774,9 +776,52 @@ Layer::BufferManager::~BufferManager() { } -status_t Layer::BufferManager::resize(size_t size) +status_t Layer::BufferManager::resize(size_t size, + const sp<SurfaceFlinger>& flinger, EGLDisplay dpy) { Mutex::Autolock _l(mLock); + + if (size < mNumBuffers) { + // Move the active texture into slot 0 + BufferData activeBufferData = mBufferData[mActiveBuffer]; + mBufferData[mActiveBuffer] = mBufferData[0]; + mBufferData[0] = activeBufferData; + mActiveBuffer = 0; + + // Free the buffers that are no longer needed. + for (size_t i = size; i < mNumBuffers; i++) { + mBufferData[i].buffer = 0; + + // Create a message to destroy the textures on SurfaceFlinger's GL + // thread. + class MessageDestroyTexture : public MessageBase { + Image mTexture; + EGLDisplay mDpy; + public: + MessageDestroyTexture(const Image& texture, EGLDisplay dpy) + : mTexture(texture), mDpy(dpy) { } + virtual bool handler() { + status_t err = Layer::BufferManager::destroyTexture( + &mTexture, mDpy); + LOGE_IF(err<0, "error destroying texture: %d (%s)", + mTexture.name, strerror(-err)); + return true; // XXX: err == 0; ???? + } + }; + + MessageDestroyTexture *msg = new MessageDestroyTexture( + mBufferData[i].texture, dpy); + + // Don't allow this texture to be cleaned up by + // BufferManager::destroy. + mBufferData[i].texture.name = -1U; + mBufferData[i].texture.image = EGL_NO_IMAGE_KHR; + + // Post the message to the SurfaceFlinger object. + flinger->postMessageAsync(msg); + } + } + mNumBuffers = size; return NO_ERROR; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index caa6d17119f1..07434cf867f7 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -177,7 +177,8 @@ private: sp<GraphicBuffer> detachBuffer(size_t index); status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer); // resize the number of active buffers - status_t resize(size_t size); + status_t resize(size_t size, const sp<SurfaceFlinger>& flinger, + EGLDisplay dpy); // ---------------------------------------------- // must be called from GL thread diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index 2cbd63cfbbb6..632615d4bf51 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -251,7 +251,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } @Override - public Phone getPhone() { + protected Phone getPhone() { return phone; } |