Merge change I50986dd4 into eclair
* changes:
Make the RegisteredSErvices Cache not allow the registered service for a type to change without first uninstalling the previous service for that type, unless the newly installed service is in the system image.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index daf4090..b116bf8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -485,7 +485,8 @@
return mResources;
}
- public Application makeApplication(boolean forceDefaultAppClass) {
+ public Application makeApplication(boolean forceDefaultAppClass,
+ Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
@@ -512,7 +513,21 @@
}
}
mActivityThread.mAllApplications.add(app);
- return mApplication = app;
+ mApplication = app;
+
+ if (instrumentation != null) {
+ try {
+ instrumentation.callApplicationOnCreate(app);
+ } catch (Exception e) {
+ if (!instrumentation.onException(app, e)) {
+ throw new RuntimeException(
+ "Unable to create application " + app.getClass().getName()
+ + ": " + e.toString(), e);
+ }
+ }
+ }
+
+ return app;
}
public void removeContextRegistrations(Context context,
@@ -2378,7 +2393,7 @@
}
try {
- Application app = r.packageInfo.makeApplication(false);
+ Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Log.v(TAG, "Performing launch of " + r);
if (localLOGV) Log.v(
@@ -2576,7 +2591,7 @@
}
try {
- Application app = packageInfo.makeApplication(false);
+ Application app = packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Log.v(
TAG, "Performing receive of " + data.intent
@@ -2730,7 +2745,7 @@
ApplicationContext context = new ApplicationContext();
context.init(packageInfo, null, this);
- Application app = packageInfo.makeApplication(false);
+ Application app = packageInfo.makeApplication(false, mInstrumentation);
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
@@ -3940,7 +3955,7 @@
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
- Application app = data.info.makeApplication(data.restrictedBackupMode);
+ Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
List<ProviderInfo> providers = data.providers;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 4684f45..bd5b07c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -36,13 +36,30 @@
import java.util.UUID;
/**
- * Represents the local Bluetooth adapter.
- *
- * <p>Use {@link #getDefaultAdapter} to get the default local Bluetooth
- * adapter.
- *
- * <p>Use the {@link BluetoothDevice} class for operations on remote Bluetooth
+ * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
+ * lets you perform fundamental Bluetooth tasks, such as initiate
+ * device discovery, query a list of bonded (paired) devices,
+ * instantiate a {@link BluetoothDevice} using a known MAC address, and create
+ * a {@link BluetoothServerSocket} to listen for connection requests from other
* devices.
+ *
+ * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
+ * adapter, call the static {@link #getDefaultAdapter} method.
+ * Fundamentally, this is your starting point for all
+ * Bluetooth actions. Once you have the local adapter, you can get a set of
+ * {@link BluetoothDevice} objects representing all paired devices with
+ * {@link #getBondedDevices()}; start device discovery with
+ * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
+ * listen for incoming connection requests with
+ * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
+ * permission and some also require the
+ * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+ *
+ * {@see BluetoothDevice}
+ * {@see BluetoothServerSocket}
*/
public final class BluetoothAdapter {
private static final String TAG = "BluetoothAdapter";
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 6210380..bc06713 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -20,25 +20,37 @@
import android.os.Parcelable;
/**
- * Represents a Bluetooth class.
+ * Represents a Bluetooth class, which describes general characteristics
+ * and capabilities of a device. For example, a Bluetooth class will
+ * specify the general device type such as a phone, a computer, or
+ * headset, and whether it's capable of services such as audio or telephony.
*
- * <p>Bluetooth Class is a 32 bit field. The format of these bits is defined at
- * http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
- * (login required). This class contains that 32 bit field, and provides
- * constants and methods to determine which Service Class(es) and Device Class
- * are encoded in that field.
+ * <p>The Bluetooth class is useful as a hint to roughly describe a device (for example to
+ * show an icon in the UI), but does not reliably describe which Bluetooth
+ * profiles or services are actually supported by a device.
*
- * <p>Every Bluetooth Class is composed of zero or more service classes, and
+ * <p>Every Bluetooth class is composed of zero or more service classes, and
* exactly one device class. The device class is further broken down into major
* and minor device class components.
*
- * <p>Class is useful as a hint to roughly describe a device (for example to
- * show an icon in the UI), but does not reliably describe which Bluetooth
- * profiles or services are actually supported by a device. Accurate service
- * discovery is done through SDP requests.
+ * <p>{@link BluetoothClass} is useful as a hint to roughly describe a device
+ * (for example to show an icon in the UI), but does not reliably describe which
+ * Bluetooth profiles or services are actually supported by a device. Accurate
+ * service discovery is done through SDP requests, which are automatically
+ * performed when creating an RFCOMM socket with {@link
+ * BluetoothDevice#createRfcommSocketToServiceRecord(UUID)} and {@link
+ * BluetoothAdapter#listenUsingRfcommWithServiceRecord(String,UUID)}</p>
*
* <p>Use {@link BluetoothDevice#getBluetoothClass} to retrieve the class for
* a remote device.
+ *
+ * <!--
+ * The Bluetooth class is a 32 bit field. The format of these bits is defined at
+ * http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
+ * (login required). This class contains that 32 bit field, and provides
+ * constants and methods to determine which Service Class(es) and Device Class
+ * are encoded in that field.
+ * -->
*/
public final class BluetoothClass implements Parcelable {
/**
@@ -91,7 +103,7 @@
}
/**
- * Bluetooth service classes.
+ * Defines all service class constants.
* <p>Each {@link BluetoothClass} encodes zero or more service classes.
*/
public static final class Service {
@@ -109,7 +121,8 @@
}
/**
- * Return true if the specified service class is supported by this class.
+ * Return true if the specified service class is supported by this
+ * {@link BluetoothClass}.
* <p>Valid service classes are the public constants in
* {@link BluetoothClass.Service}. For example, {@link
* BluetoothClass.Service#AUDIO}.
@@ -122,17 +135,22 @@
}
/**
- * Bluetooth device classes.
+ * Defines all device class constants.
* <p>Each {@link BluetoothClass} encodes exactly one device class, with
* major and minor components.
* <p>The constants in {@link
* BluetoothClass.Device} represent a combination of major and minor
- * components (the complete device class). The constants in {@link
- * BluetoothClass.Device.Major} represent just the major device classes.
+ * device components (the complete device class). The constants in {@link
+ * BluetoothClass.Device.Major} represent only major device classes.
+ * <p>See {@link BluetoothClass.Service} for service class constants.
*/
public static class Device {
private static final int BITMASK = 0x1FFC;
+ /**
+ * Defines all major device class constants.
+ * <p>See {@link BluetoothClass.Device} for minor classes.
+ */
public static class Major {
private static final int BITMASK = 0x1F00;
@@ -215,7 +233,7 @@
}
/**
- * Return the major device class component of this Bluetooth class.
+ * Return the major device class component of this {@link BluetoothClass}.
* <p>Values returned from this function can be compared with the
* public constants in {@link BluetoothClass.Device.Major} to determine
* which major class is encoded in this Bluetooth class.
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 849e6c7..6cb9770 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -31,16 +31,31 @@
import java.util.UUID;
/**
- * Represents a remote Bluetooth device.
- *
- * <p>Use {@link BluetoothAdapter#getRemoteDevice} to create a {@link
- * BluetoothDevice}.
+ * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
+ * create a connection with the repective device or query information about
+ * it, such as the name, address, class, and bonding state.
*
* <p>This class is really just a thin wrapper for a Bluetooth hardware
* address. Objects of this class are immutable. Operations on this class
* are performed on the remote Bluetooth hardware address, using the
* {@link BluetoothAdapter} that was used to create this {@link
* BluetoothDevice}.
+ *
+ * <p>To get a {@link BluetoothDevice}, use
+ * {@link BluetoothAdapter#getRemoteDevice(String)
+ * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
+ * of a known MAC address (which you can get through device discovery with
+ * {@link BluetoothAdapter}) or get one from the set of bonded devices
+ * returned by {@link BluetoothAdapter#getBondedDevices()
+ * BluetoothAdapter.getBondedDevices()}. You can then open a
+ * {@link BluetoothSocket} for communciation with the remote device, using
+ * {@link #createRfcommSocketToServiceRecord(UUID)}.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * {@see BluetoothAdapter}
+ * {@see BluetoothSocket}
*/
public final class BluetoothDevice implements Parcelable {
private static final String TAG = "BluetoothDevice";
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 605bdc1..1b23f6c 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -27,29 +27,31 @@
* <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
* {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
* side, use a {@link BluetoothServerSocket} to create a listening server
- * socket. It will return a new, connected {@link BluetoothSocket} on an
- * accepted connection. On the client side, use the same
- * {@link BluetoothSocket} object to both intiate the outgoing connection,
- * and to manage the connected socket.
+ * socket. When a connection is accepted by the {@link BluetoothServerSocket},
+ * it will return a new {@link BluetoothSocket} to manage the connection.
+ * On the client side, use a single {@link BluetoothSocket} to both intiate
+ * an outgoing connection and to manage the connection.
*
- * <p>The most common type of Bluetooth Socket is RFCOMM. RFCOMM is a
- * connection orientated, streaming transport over Bluetooth. It is also known
- * as the Serial Port Profile (SPP).
+ * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
+ * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
+ * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
*
- * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to create
- * a new {@link BluetoothSocket} ready for an outgoing connection to a remote
- * {@link BluetoothDevice}.
+ * <p>To create a listenting {@link BluetoothServerSocket} that's ready for
+ * incoming connections, use
+ * {@link BluetoothAdapter#listenUsingRfcommWithServiceRecord
+ * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}. Then call
+ * {@link #accept()} to listen for incoming connection requests. This call
+ * will block until a connection is established, at which point, it will return
+ * a {@link BluetoothSocket} to manage the connection.
*
- * <p>Use {@link BluetoothAdapter#listenUsingRfcommWithServiceRecord} to
- * create a listening {@link BluetoothServerSocket} ready for incoming
- * connections to the local {@link BluetoothAdapter}.
- *
- * <p>{@link BluetoothSocket} and {@link BluetoothServerSocket} are thread
+ * <p>{@link BluetoothServerSocket} is thread
* safe. In particular, {@link #close} will always immediately abort ongoing
- * operations and close the socket.
+ * operations and close the server socket.
*
- * <p>All methods on a {@link BluetoothServerSocket} require
- * {@link android.Manifest.permission#BLUETOOTH}
+ * <p class="note"><strong>Note:</strong>
+ * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * {@see BluetoothSocket}
*/
public final class BluetoothServerSocket implements Closeable {
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 7e72590..dbcc758 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -33,29 +33,41 @@
* <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
* {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
* side, use a {@link BluetoothServerSocket} to create a listening server
- * socket. It will return a new, connected {@link BluetoothSocket} on an
- * accepted connection. On the client side, use the same
- * {@link BluetoothSocket} object to both intiate the outgoing connection,
- * and to manage the connected socket.
+ * socket. When a connection is accepted by the {@link BluetoothServerSocket},
+ * it will return a new {@link BluetoothSocket} to manage the connection.
+ * On the client side, use a single {@link BluetoothSocket} to both intiate
+ * an outgoing connection and to manage the connection.
*
- * <p>The most common type of Bluetooth Socket is RFCOMM. RFCOMM is a
- * connection orientated, streaming transport over Bluetooth. It is also known
- * as the Serial Port Profile (SPP).
+ * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
+ * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
+ * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
*
- * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to create
- * a new {@link BluetoothSocket} ready for an outgoing connection to a remote
- * {@link BluetoothDevice}.
+ * <p>To create a {@link BluetoothSocket} for connecting to a known device, use
+ * {@link BluetoothDevice#createRfcommSocketToServiceRecord
+ * BluetoothDevice.createRfcommSocketToServiceRecord()}.
+ * Then call {@link #connect()} to attempt a connection to the remote device.
+ * This call will block until a connection is established or the connection
+ * fails.
*
- * <p>Use {@link BluetoothAdapter#listenUsingRfcommWithServiceRecord} to
- * create a listening {@link BluetoothServerSocket} ready for incoming
- * connections to the local {@link BluetoothAdapter}.
+ * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the
+ * {@link BluetoothServerSocket} documentation.
*
- * <p>{@link BluetoothSocket} and {@link BluetoothServerSocket} are thread
+ * <p>Once the socket is connected, whether initiated as a client or accepted
+ * as a server, open the IO streams by calling {@link #getInputStream} and
+ * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream}
+ * and {@link java.io.OutputStream} objects, respectively, which are
+ * automatically connected to the socket.
+ *
+ * <p>{@link BluetoothSocket} is thread
* safe. In particular, {@link #close} will always immediately abort ongoing
* operations and close the socket.
*
- * <p>All methods on a {@link BluetoothSocket} require
- * {@link android.Manifest.permission#BLUETOOTH}
+ * <p class="note"><strong>Note:</strong>
+ * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * {@see BluetoothServerSocket}
+ * {@see java.io.InputStream}
+ * {@see java.io.OutputStream}
*/
public final class BluetoothSocket implements Closeable {
private static final String TAG = "BluetoothSocket";
diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html
index 79abf0c..4f0755e 100644
--- a/core/java/android/bluetooth/package.html
+++ b/core/java/android/bluetooth/package.html
@@ -1,13 +1,109 @@
<HTML>
<BODY>
-Provides classes that manage Bluetooth functionality on the device.
-<p>
-The Bluetooth APIs allow applications can connect and disconnect headsets, or scan
-for other kinds of Bluetooth devices and pair them. Further control includes the
-ability to write and modify the local Service Discovery Protocol (SDP) database,
-query the SDP database of other Bluetooth devices, establish RFCOMM
-channels/sockets on Android, and connect to specified sockets on other devices.
+Provides classes that manage Bluetooth functionality, such as scanning for
+devices, connecting with devices, and managing data transfer between devices.
+
+<p>The Bluetooth APIs let applications:</p>
+<ul>
+ <li>Scan for other Bluetooth devices</li>
+ <li>Query the local Bluetooth adapter for paired Bluetooth devices</li>
+ <li>Establish RFCOMM channels/sockets</li>
+ <li>Connect to specified sockets on other devices</li>
+ <li>Transfer data to and from other devices</li>
+</ul>
+
+<p class="note"><strong>Note:</strong>
+To perform Bluetooth communication using these APIs, an application must
+declare the {@link android.Manifest.permission#BLUETOOTH} permission. Some
+additional functionality, such as requesting device discovery and
+pairing also requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+permission.
</p>
-<p>Remember, not all Android devices are guaranteed to have Bluetooth functionality.</p>
+
+<h3>Overview</h3>
+
+<p>Here's a basic introduction to the Bluetooth classes:</p>
+<dl>
+ <dt>{@link android.bluetooth.BluetoothAdapter}</dt>
+ <dd>This represents the local Bluetooth adapter, which is essentially the
+ entry-point to performing any interaction with Bluetooth. With it, you can
+ discover other Bluetooth devices, query a list of bonded (paired) devices,
+ initialize a {@link android.bluetooth.BluetoothDevice} using a known MAC
+ address, and create a {@link android.bluetooth.BluetoothServerSocket} to
+ listen for communications from other devices.</dd>
+
+ <dt>{@link android.bluetooth.BluetoothDevice}</dt>
+ <dd>This represents a remote Bluetooth device. Use this to request a
+ connection with a remote device through a
+ {@link android.bluetooth.BluetoothSocket}
+ or query information about the device such as its name, address, class, and
+ bonding state.</dd>
+
+ <dt>{@link android.bluetooth.BluetoothSocket}</dt>
+ <dd>This represents the interface for a Bluetooth socket
+ (similar to a TCP client-side {@link java.net.Socket}). This is the
+ connection point that allows an app to transfer data with another Bluetooth
+ device via {@link java.io.InputStream} and {@link java.io.OutputStream}.</dd>
+ <dt>{@link android.bluetooth.BluetoothServerSocket}</dt>
+
+ <dd>This represents an open server socket that listens for incoming requests
+ (similar to a TCP server-side {@link java.net.ServerSocket}).
+ When attempting to connect two Android devices, one device will need to open
+ a server socket with this class. When a connection is accepted, a new
+ {@link android.bluetooth.BluetoothSocket} will be returned,
+ which can be used to manage the connection and transfer data.</dd>
+
+ <dt>{@link android.bluetooth.BluetoothClass}</dt>
+ <dd>This represents the Bluetooth class for a device which describes general
+ characteristics and capabilities of a device. This class and its subclasses
+ don't provide any actual functionality. The sub-classes are entirely composed
+ of constants for the device and service class definitions.</dd>
+</dl>
+
+
+<h3>Example Procedure</h3>
+
+<p>For example, here's an pseudo-code procedure for discovering and
+connecting a remote device, and transfering data:</p>
+
+<ol>
+ <li>Register a {@link android.content.BroadcastReceiver} that accepts the
+ {@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent.</li>
+ <li>Call {@link android.bluetooth.BluetoothAdapter#getDefaultAdapter} to
+ retrieve the Android system's local
+ {@link android.bluetooth.BluetoothAdapter}.</li>
+ <li>Call {@link android.bluetooth.BluetoothAdapter#startDiscovery()
+ BluetoothAdapter.startDiscovery()} to scan for local devices. This is where
+ the BroadcastReceiver comes in; Android now scans for devices and will
+ broadcast the {@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent
+ for each remote device discovered. The
+ {@link android.content.BroadcastReceiver}
+ you created will receive each Intent.</li>
+ <li>The {@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent
+ includes the {@link android.bluetooth.BluetoothDevice#EXTRA_DEVICE}
+ Parcelable extra, which is a {@link android.bluetooth.BluetoothDevice}
+ object. Extract this from the Intent and call
+ {@link android.bluetooth.BluetoothDevice#createRfcommSocketToServiceRecord(java.util.UUID)
+ BluetoothDevice.createRfcommSocketToServiceRecord()}
+ to open a {@link android.bluetooth.BluetoothSocket} with a chosen
+ remote device.</li>
+ <li>Call {@link android.bluetooth.BluetoothSocket#connect()
+ BluetoothSocket.connect()} to connect with the remote device.</li>
+ <li>When successfully connected, call
+ {@link android.bluetooth.BluetoothSocket#getInputStream()
+ BluetoothSocket.getInputStream()} and/or
+ {@link android.bluetooth.BluetoothSocket#getOutputStream()
+ BluetoothSocket.getOutputStream()} to retreive an
+ {@link java.io.InputStream} and {@link java.io.OutputStream}, respectively,
+ which are hooked into the socket.</li>
+ <li>Use {@link java.io.InputStream#read(byte[]) InputStream.read()} and
+ {@link java.io.OutputStream#write(byte[]) OutputStream.write()} to transfer
+ data.</li>
+</ol>
+
+
+
+<p class="note"><strong>Note:</strong>
+Not all Android devices are guaranteed to have Bluetooth functionality.</p>
</BODY>
</HTML>
diff --git a/core/java/android/service/wallpaper/IWallpaperEngine.aidl b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
index bbd9dde..37e6133 100644
--- a/core/java/android/service/wallpaper/IWallpaperEngine.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperEngine.aidl
@@ -16,11 +16,14 @@
package android.service.wallpaper;
+import android.view.MotionEvent;
+
/**
* @hide
*/
oneway interface IWallpaperEngine {
void setDesiredSize(int width, int height);
void setVisibility(boolean visible);
+ void dispatchPointer(in MotionEvent event);
void destroy();
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e79832b..b29d837 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -746,6 +746,12 @@
mCaller.sendMessage(msg);
}
+ public void dispatchPointer(MotionEvent event) {
+ if (mEngine != null) {
+ mEngine.mWindow.onDispatchPointer(event, event.getEventTime(), false);
+ }
+ }
+
public void destroy() {
Message msg = mCaller.obtainMessage(DO_DETACH);
mCaller.sendMessage(msg);
@@ -805,6 +811,7 @@
mEngine.mPendingMove = null;
}
}
+ if (DEBUG) Log.v(TAG, "Delivering touch event: " + ev);
mEngine.onTouchEvent(ev);
ev.recycle();
} break;
diff --git a/docs/html/sdk/adding-components.jd b/docs/html/sdk/adding-components.jd
index 967c3521..bc82170 100644
--- a/docs/html/sdk/adding-components.jd
+++ b/docs/html/sdk/adding-components.jd
@@ -54,8 +54,13 @@
<h2 id="InstallingComponents">Installing SDK Components</h2>
-<p>Use the Android SDK and AVD Manager to install new SDK components.
-You can launch the SDK and AVD Manager in one of these ways:</p>
+<p>Use the Android SDK and AVD Manager to install new SDK components. </p>
+
+<p class="caution"><strong>Important:</strong> Before you install SDK components,
+we recommend that you disable any antivirus programs that may be running on
+your computer.</p>
+
+<p>You can launch the SDK and AVD Manager in one of these ways:</p>
<ul>
<li>Execute the {@code android}</a> tool command with no options. If you
haven't used the tool before, change to the <code><sdk>/tools</code>
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index edc77e8..261b49f 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -26,8 +26,8 @@
</div>
</div>
-<p>This page describes how to install the Android SDK and set up your
-development environment for the first time.</p>
+<p>This page describes how to install the latest version of the Android SDK
+and set up your development environment for the first time.</p>
<p>If you encounter any problems during installation, see the
<a href="#troubleshooting">Troubleshooting</a> section at the bottom of
@@ -36,14 +36,14 @@
<h4>Updating?</h4>
<p>If you are currently using the Android 1.6 SDK, you do not necessarily need
-to install the new SDK, since your existing SDK already includes the Android SDK
-and AVD Manager tool. To develop against the new Android 2.0 platform, for
-example, you could just download the updated SDK Tools (Revision 3) and the
-Android 2.0 platform into your existing SDK.</p>
+to install a newer SDK, since you can already update the platforms, tools, and
+other components using the Android SDK and AVD Manager tool. To develop against
+the latest Android platform, for example, you could just download the latest SDK
+Tools and then add the new Android platform into your existing SDK.</p>
<p>If you are using Android 1.5 SDK or older, you should install the new SDK as
described in this document and move your application projects to the new
-environment. </p>
+SDK environment. </p>
<h2 id="Preparing">Prepare for Installation</h2>
@@ -65,13 +65,15 @@
<h2 id="Installing">Download and Install the SDK</h2>
<p>Download the SDK package that is appropriate for your development computer.
-Unpack the Android SDK archive to a suitable location on your machine. By
-default, the SDK files are unpacked into a directory named
-<code>android-sdk-<machine-platform></code>. </p>
+You can get the latest version from the <a href="{@docRoot}sdk/index.html">SDK
+download page</a>.</p>
-<p>Make a note of the name and location of the unpacked SDK directory on your
-system — you will need to refer to the SDK directory later, when setting
-up the ADT plugin or when using the SDK tools.</p>
+<p>After downloading, unpack the Android SDK archive to a suitable location on your
+machine. By default, the SDK files are unpacked into a directory named
+<code>android-sdk-<machine-platform></code>. Make a note of the name and
+location of the unpacked SDK directory on your system — you will need to
+refer to the SDK directory later, when setting up the ADT plugin or when using
+the SDK tools.</p>
<p>Optionally, you may want to add the location of the SDK's primary
<code>tools</code> directory to your system <code>PATH</code>. The primary
@@ -128,7 +130,7 @@
<h2 id="components">Add Android Platforms and Other Components</h2>
-<div class="sidebox-wrapper">
+<div class="sidebox-wrapper" style="margin-right:2.5em;">
<div class="sidebox">
<p>The <strong>Android SDK and AVD Manager</strong> tool is pre-installed in
your SDK. Using the tool is a key part of performing the initial setup of your
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 9a06d13..dbee451 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -40,11 +40,13 @@
return err;
}
+// Warning: The filedescriptor passed into this method will only be valid until
+// the method returns, if you want to keep it, dup it!
status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
reset();
- mPlayer = new MediaPlayerImpl(fd, offset, length);
+ mPlayer = new MediaPlayerImpl(dup(fd), offset, length);
status_t err = mPlayer->initCheck();
if (err != OK) {
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 6908220..246f9fc 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -19,6 +19,7 @@
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
index 5e830a8..9fb49b1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkTest.java
@@ -42,6 +42,7 @@
import java.io.File;
import java.io.FileDescriptor;
+import java.net.InetAddress;
public class MediaFrameworkTest extends Activity {
@@ -142,4 +143,9 @@
return super.onKeyDown(keyCode, event);
}
+
+ public static boolean checkStreamingServer() throws Exception {
+ InetAddress address = InetAddress.getByAddress(MediaNames.STREAM_SERVER);
+ return address.isReachable(10000);
+ }
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 3b69df898..5127255 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -489,6 +489,7 @@
};
//Streaming test files
+ public static final byte [] STREAM_SERVER = new byte[] {(byte)75,(byte)17,(byte)48,(byte)204};
public static final String STREAM_H264_480_360_1411k =
"http://75.17.48.204:10088/yslau/stress_media/h264_regular.mp4";
public static final String STREAM_WMV =
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index 5725c44..4e30f91 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -439,6 +439,7 @@
@MediumTest
public void testPrepareAsyncReset() throws Exception {
+ assertTrue(MediaFrameworkTest.checkStreamingServer());
boolean isReset = CodecTest.prepareAsyncReset(MediaNames.STREAM_MP3);
assertTrue("PrepareAsync Reset", isReset);
}
@@ -471,6 +472,7 @@
@LargeTest
public void testStreamPrepareAsyncCallback() throws Exception {
+ assertTrue(MediaFrameworkTest.checkStreamingServer());
boolean onPrepareSuccess =
CodecTest.prepareAsyncCallback(MediaNames.STREAM_H264_480_360_1411k, false);
assertTrue("StreamH264PrepareAsyncCallback", onPrepareSuccess);
@@ -478,6 +480,7 @@
@LargeTest
public void testStreamPrepareAsyncCallbackReset() throws Exception {
+ assertTrue(MediaFrameworkTest.checkStreamingServer());
boolean onPrepareSuccess =
CodecTest.prepareAsyncCallback(MediaNames.STREAM_H264_480_360_1411k, true);
assertTrue("StreamH264PrepareAsyncCallback", onPrepareSuccess);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index fdb43da..b476e01 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -64,6 +64,7 @@
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
try {
+ assertTrue(MediaFrameworkTest.checkStreamingServer());
for (int i = 0; i < NUMBER_OF_STRESS_LOOPS; i++) {
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(MediaNames.STREAM_H264_480_360_1411k);
diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java
index 65663b1..05b498c 100644
--- a/obex/javax/obex/ClientOperation.java
+++ b/obex/javax/obex/ClientOperation.java
@@ -269,7 +269,7 @@
if (mPrivateOutput == null) {
// there are 3 bytes operation headers and 3 bytes body headers //
- mPrivateOutput = new PrivateOutputStream(this, mMaxPacketSize - 6);
+ mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
}
mPrivateOutputOpen = true;
@@ -278,7 +278,13 @@
}
public int getMaxPacketSize() {
- return mMaxPacketSize - 6;
+ return mMaxPacketSize - 6 - getHeaderLength();
+ }
+
+ public int getHeaderLength() {
+ // OPP may need it
+ byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
+ return headerArray.length;
}
/**
diff --git a/obex/javax/obex/Operation.java b/obex/javax/obex/Operation.java
index 20653f2..25656ed 100644
--- a/obex/javax/obex/Operation.java
+++ b/obex/javax/obex/Operation.java
@@ -163,6 +163,8 @@
long getLength();
+ int getHeaderLength();
+
String getType();
InputStream openInputStream() throws IOException;
diff --git a/obex/javax/obex/ServerOperation.java b/obex/javax/obex/ServerOperation.java
index 504fe35..07a3a53 100644
--- a/obex/javax/obex/ServerOperation.java
+++ b/obex/javax/obex/ServerOperation.java
@@ -124,21 +124,30 @@
* It is a PUT request.
*/
mGetOperation = false;
- } else {
+
+ /*
+ * Determine if the final bit is set
+ */
+ if ((request & 0x80) == 0) {
+ finalBitSet = false;
+ } else {
+ finalBitSet = true;
+ mRequestFinished = true;
+ }
+ } else if ((request == 0x03) || (request == 0x83)) {
/*
* It is a GET request.
*/
mGetOperation = true;
- }
- /*
- * Determine if the final bit is set
- */
- if ((request & 0x80) == 0) {
+ // For Get request, final bit set is decided by server side logic
finalBitSet = false;
+
+ if (request == 0x83) {
+ mRequestFinished = true;
+ }
} else {
- finalBitSet = true;
- mRequestFinished = true;
+ throw new IOException("ServerOperation can not handle such request");
}
int length = in.read();
@@ -216,12 +225,9 @@
}
// wait for get request finished !!!!
- while (mGetOperation && !finalBitSet) {
+ while (mGetOperation && !mRequestFinished) {
sendReply(ResponseCodes.OBEX_HTTP_CONTINUE);
}
- if (finalBitSet && mGetOperation) {
- mRequestFinished = true;
- }
}
public boolean isValidBody() {
@@ -333,6 +339,12 @@
out.write(headerArray);
}
+ // For Get operation: if response code is OBEX_HTTP_OK, then this is the
+ // last packet; so set finalBitSet to true.
+ if (mGetOperation && type == ResponseCodes.OBEX_HTTP_OK) {
+ finalBitSet = true;
+ }
+
if ((finalBitSet) || (headerArray.length < (mMaxPacketLength - 20))) {
if (bodyLength > 0) {
/*
@@ -410,9 +422,10 @@
}
} else {
- if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)
- || (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL)) {
+ if ((headerID == ObexHelper.OBEX_OPCODE_PUT_FINAL)) {
finalBitSet = true;
+ } else if (headerID == ObexHelper.OBEX_OPCODE_GET_FINAL) {
+ mRequestFinished = true;
}
/*
@@ -584,7 +597,20 @@
}
public int getMaxPacketSize() {
- return mMaxPacketLength - 6;
+ return mMaxPacketLength - 6 - getHeaderLength();
+ }
+
+ public int getHeaderLength() {
+ long id = mListener.getConnectionId();
+ if (id == -1) {
+ replyHeader.mConnectionID = null;
+ } else {
+ replyHeader.mConnectionID = ObexHelper.convertToByteArray(id);
+ }
+
+ byte[] headerArray = ObexHelper.createHeader(replyHeader, false);
+
+ return headerArray.length;
}
/**
@@ -623,7 +649,7 @@
}
if (mPrivateOutput == null) {
- mPrivateOutput = new PrivateOutputStream(this, mMaxPacketLength - 6);
+ mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
}
mPrivateOutputOpen = true;
return mPrivateOutput;
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 0330163..9ca57ba 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -18,7 +18,6 @@
import java.io.Writer;
import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
@@ -943,6 +942,9 @@
* to a Renderer instance to do the actual drawing. Can be configured to
* render continuously or on request.
*
+ * All potentially blocking synchronization is done through the
+ * sGLThreadManager object. This avoids multiple-lock ordering issues.
+ *
*/
class GLThread extends Thread {
GLThread(Renderer renderer) {
@@ -962,51 +964,31 @@
Log.i("GLThread", "starting tid=" + getId());
}
- /*
- * When the android framework launches a second instance of
- * an activity, the new instance's onCreate() method may be
- * called before the first instance returns from onDestroy().
- *
- * This semaphore ensures that only one instance at a time
- * accesses EGL.
- */
try {
guardedRun();
} catch (InterruptedException e) {
// fall thru and exit normally
} finally {
- synchronized(this) {
- if (LOG_THREADS) {
- Log.i("GLThread", "exiting tid=" + getId());
- }
- mDone = true;
- notifyAll();
- }
+ sGLThreadManager.threadExiting(this);
}
}
- private void startEgl() throws InterruptedException {
- if (! mHaveEgl) {
- mHaveEgl = true;
- sGLThreadManager.start(this);
- mEglHelper.start();
- }
- }
-
- private void stopEgl() {
+ /*
+ * This private method should only be called inside a
+ * synchronized(sGLThreadManager) block.
+ */
+ private void stopEglLocked() {
if (mHaveEgl) {
mHaveEgl = false;
mEglHelper.destroySurface();
mEglHelper.finish();
- sGLThreadManager.end(this);
+ sGLThreadManager.releaseEglSurface(this);
}
}
private void guardedRun() throws InterruptedException {
mEglHelper = new EglHelper();
try {
- startEgl();
-
GL10 gl = null;
boolean tellRendererSurfaceCreated = true;
boolean tellRendererSurfaceChanged = true;
@@ -1015,63 +997,97 @@
* This is our main activity thread's loop, we go until
* asked to quit.
*/
- while (!mDone) {
-
+ while (!isDone()) {
/*
* Update the asynchronous state (window size)
*/
- int w, h;
- boolean changed;
+ int w = 0;
+ int h = 0;
+ boolean changed = false;
boolean needStart = false;
- synchronized (this) {
+ boolean eventsWaiting = false;
+
+ synchronized (sGLThreadManager) {
+ while (true) {
+ // Manage acquiring and releasing the SurfaceView
+ // surface and the EGL surface.
+ if (mPaused) {
+ stopEglLocked();
+ }
+ if (!mHasSurface) {
+ if (!mWaitingForSurface) {
+ stopEglLocked();
+ mWaitingForSurface = true;
+ sGLThreadManager.notifyAll();
+ }
+ } else {
+ if (!mHaveEgl) {
+ if (sGLThreadManager.tryAcquireEglSurface(this)) {
+ mHaveEgl = true;
+ mEglHelper.start();
+ mRequestRender = true;
+ needStart = true;
+ }
+ }
+ }
+
+ // Check if we need to wait. If not, update any state
+ // that needs to be updated, copy any state that
+ // needs to be copied, and use "break" to exit the
+ // wait loop.
+
+ if (mDone) {
+ return;
+ }
+
+ if (mEventsWaiting) {
+ eventsWaiting = true;
+ mEventsWaiting = false;
+ break;
+ }
+
+ if ( (! mPaused) && mHasSurface && mHaveEgl
+ && (mWidth > 0) && (mHeight > 0)
+ && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))
+ ) {
+ changed = mSizeChanged;
+ w = mWidth;
+ h = mHeight;
+ mSizeChanged = false;
+ mRequestRender = false;
+ if (mHasSurface && mWaitingForSurface) {
+ changed = true;
+ mWaitingForSurface = false;
+ sGLThreadManager.notifyAll();
+ }
+ break;
+ }
+
+ // By design, this is the only place where we wait().
+
+ if (LOG_THREADS) {
+ Log.i("GLThread", "waiting tid=" + getId());
+ }
+ sGLThreadManager.wait();
+ }
+ } // end of synchronized(sGLThreadManager)
+
+ /*
+ * Handle queued events
+ */
+ if (eventsWaiting) {
Runnable r;
while ((r = getEvent()) != null) {
r.run();
- }
- if (mPaused) {
- stopEgl();
- needStart = true;
- }
- while(true) {
- if (!mHasSurface) {
- if (!mWaitingForSurface) {
- stopEgl();
- mWaitingForSurface = true;
- notifyAll();
- }
- } else {
- boolean shouldHaveEgl = sGLThreadManager.shouldHaveEgl(this);
- if (mHaveEgl && (!shouldHaveEgl)) {
- stopEgl();
- } else if ((!mHaveEgl) && shouldHaveEgl) {
- startEgl();
- needStart = true;
- }
+ if (isDone()) {
+ return;
}
- if (!needToWait()) {
- break;
- }
- if (LOG_THREADS) {
- Log.i("GLThread", "needToWait tid=" + getId());
- }
- wait();
}
- if (mDone) {
- break;
- }
- changed = mSizeChanged;
- w = mWidth;
- h = mHeight;
- mSizeChanged = false;
- mRequestRender = false;
- if (mHasSurface && mWaitingForSurface) {
- changed = true;
- mWaitingForSurface = false;
- notifyAll();
- }
+ // Go back and see if we need to wait to render.
+ continue;
}
+
if (needStart) {
- startEgl();
tellRendererSurfaceCreated = true;
changed = true;
}
@@ -1102,71 +1118,63 @@
/*
* clean-up everything...
*/
- stopEgl();
+ synchronized (sGLThreadManager) {
+ stopEglLocked();
+ }
}
}
- private boolean needToWait() {
- if (mDone) {
- return false;
+ private boolean isDone() {
+ synchronized (sGLThreadManager) {
+ return mDone;
}
-
- if (mPaused || (! mHasSurface) || (! mHaveEgl)) {
- return true;
- }
-
- if ((mWidth > 0) && (mHeight > 0) && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {
- return false;
- }
-
- return true;
}
public void setRenderMode(int renderMode) {
if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
throw new IllegalArgumentException("renderMode");
}
- synchronized(this) {
+ synchronized(sGLThreadManager) {
mRenderMode = renderMode;
if (renderMode == RENDERMODE_CONTINUOUSLY) {
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
}
public int getRenderMode() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
return mRenderMode;
}
}
public void requestRender() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
mRequestRender = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void surfaceCreated() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceCreated tid=" + getId());
}
mHasSurface = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void surfaceDestroyed() {
- synchronized(this) {
+ synchronized(sGLThreadManager) {
if (LOG_THREADS) {
Log.i("GLThread", "surfaceDestroyed tid=" + getId());
}
mHasSurface = false;
- notifyAll();
+ sGLThreadManager.notifyAll();
while(!mWaitingForSurface && isAlive() && ! mDone) {
try {
- wait();
+ sGLThreadManager.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
@@ -1175,35 +1183,35 @@
}
public void onPause() {
- synchronized (this) {
+ synchronized (sGLThreadManager) {
mPaused = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void onResume() {
- synchronized (this) {
+ synchronized (sGLThreadManager) {
mPaused = false;
mRequestRender = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void onWindowResize(int w, int h) {
- synchronized (this) {
+ synchronized (sGLThreadManager) {
mWidth = w;
mHeight = h;
mSizeChanged = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
}
public void requestExitAndWait() {
// don't call this from GLThread thread or it is a guaranteed
// deadlock!
- synchronized(this) {
+ synchronized(sGLThreadManager) {
mDone = true;
- notifyAll();
+ sGLThreadManager.notifyAll();
}
try {
join();
@@ -1219,6 +1227,10 @@
public void queueEvent(Runnable r) {
synchronized(this) {
mEventQueue.add(r);
+ synchronized(sGLThreadManager) {
+ mEventsWaiting = true;
+ sGLThreadManager.notifyAll();
+ }
}
}
@@ -1232,6 +1244,8 @@
return null;
}
+ // Once the thread is started, all accesses to the following member
+ // variables are protected by the sGLThreadManager monitor
private boolean mDone;
private boolean mPaused;
private boolean mHasSurface;
@@ -1241,6 +1255,9 @@
private int mHeight;
private int mRenderMode;
private boolean mRequestRender;
+ private boolean mEventsWaiting;
+ // End of member variables protected by the sGLThreadManager monitor.
+
private Renderer mRenderer;
private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
private EglHelper mEglHelper;
@@ -1286,37 +1303,43 @@
}
}
- static class GLThreadManager {
- public boolean shouldHaveEgl(GLThread thread) {
- synchronized(this) {
- return thread == mMostRecentGLThread || mMostRecentGLThread == null;
+ private static class GLThreadManager {
+
+ public synchronized void threadExiting(GLThread thread) {
+ if (LOG_THREADS) {
+ Log.i("GLThread", "exiting tid=" + thread.getId());
}
+ thread.mDone = true;
+ if (mEglOwner == thread) {
+ mEglOwner = null;
+ }
+ notifyAll();
}
- public void start(GLThread thread) throws InterruptedException {
- GLThread oldThread = null;
- synchronized(this) {
- oldThread = mMostRecentGLThread;
- mMostRecentGLThread = thread;
+
+ /*
+ * Tries once to acquire the right to use an EGL
+ * surface. Does not block.
+ * @return true if the right to use an EGL surface was acquired.
+ */
+ public synchronized boolean tryAcquireEglSurface(GLThread thread) {
+ if (mEglOwner == thread || mEglOwner == null) {
+ mEglOwner = thread;
+ notifyAll();
+ return true;
}
- if (oldThread != null) {
- synchronized(oldThread) {
- oldThread.notifyAll();
- }
- }
- sEglSemaphore.acquire();
+ return false;
}
- public void end(GLThread thread) {
- sEglSemaphore.release();
- synchronized(this) {
- if (mMostRecentGLThread == thread) {
- mMostRecentGLThread = null;
- }
+
+ public synchronized void releaseEglSurface(GLThread thread) {
+ if (mEglOwner == thread) {
+ mEglOwner = null;
}
+ notifyAll();
}
- private GLThread mMostRecentGLThread;
+
+ private GLThread mEglOwner;
}
- private static final Semaphore sEglSemaphore = new Semaphore(1);
private static final GLThreadManager sGLThreadManager = new GLThreadManager();
private boolean mSizeChanged = true;
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index 3e3cf06..88074c2 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -54,6 +54,16 @@
static final int LIGHT_FLASH_TIMED = 1;
static final int LIGHT_FLASH_HARDWARE = 2;
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ static final int BRIGHTNESS_MODE_USER = 0;
+
+ /**
+ * Light brightness is managed by a light sensor.
+ */
+ static final int BRIGHTNESS_MODE_SENSOR = 1;
+
private final LinkedList<Vibration> mVibrations;
private Vibration mCurrentVibration;
@@ -266,21 +276,21 @@
}
void setLightOff_UNCHECKED(int light) {
- setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0);
+ setLight_native(mNativePointer, light, 0, LIGHT_FLASH_NONE, 0, 0, 0);
}
- void setLightBrightness_UNCHECKED(int light, int brightness) {
+ void setLightBrightness_UNCHECKED(int light, int brightness, int brightnessMode) {
int b = brightness & 0x000000ff;
b = 0xff000000 | (b << 16) | (b << 8) | b;
- setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0);
+ setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
void setLightColor_UNCHECKED(int light, int color) {
- setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0);
+ setLight_native(mNativePointer, light, color, LIGHT_FLASH_NONE, 0, 0, 0);
}
void setLightFlashing_UNCHECKED(int light, int color, int mode, int onMS, int offMS) {
- setLight_native(mNativePointer, light, color, mode, onMS, offMS);
+ setLight_native(mNativePointer, light, color, mode, onMS, offMS, 0);
}
public void setAttentionLight(boolean on, int color) {
@@ -289,7 +299,7 @@
mAttentionLightOn = on;
mPulsing = false;
setLight_native(mNativePointer, LIGHT_ID_ATTENTION, color,
- LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0);
+ LIGHT_FLASH_HARDWARE, on ? 3 : 0, 0, 0);
}
}
@@ -304,7 +314,7 @@
if (!mAttentionLightOn && !mPulsing) {
mPulsing = true;
setLight_native(mNativePointer, LIGHT_ID_ATTENTION, 0x00ffffff,
- LIGHT_FLASH_HARDWARE, 7, 0);
+ LIGHT_FLASH_HARDWARE, 7, 0, 0);
mH.sendMessageDelayed(Message.obtain(mH, 1), 3000);
}
}
@@ -321,7 +331,7 @@
mPulsing = false;
setLight_native(mNativePointer, LIGHT_ID_ATTENTION,
mAttentionLightOn ? 0xffffffff : 0,
- LIGHT_FLASH_NONE, 0, 0);
+ LIGHT_FLASH_NONE, 0, 0, 0);
}
}
}
@@ -484,7 +494,7 @@
private static native void finalize_native(int ptr);
private static native void setLight_native(int ptr, int light, int color, int mode,
- int onMS, int offMS);
+ int onMS, int offMS, int brightnessMode);
private final Context mContext;
private final PowerManager.WakeLock mWakeLock;
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 3000e9d..e1425d4 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1324,8 +1324,13 @@
enableLightSensor(on);
if (!on) {
// make sure button and key backlights are off too
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, 0);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, 0);
+ int brightnessMode = (mUseSoftwareAutoBrightness
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, 0,
+ brightnessMode);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, 0,
+ brightnessMode);
// clear current value so we will update based on the new conditions
// when the sensor is reenabled.
mLightSensorValue = -1;
@@ -1680,14 +1685,23 @@
}
private void setLightBrightness(int mask, int value) {
+ int brightnessMode = (mAutoBrightessEnabled
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
if ((mask & SCREEN_BRIGHT_BIT) != 0) {
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, value);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, value,
+ brightnessMode);
}
+ brightnessMode = (mUseSoftwareAutoBrightness
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
if ((mask & BUTTON_BRIGHT_BIT) != 0) {
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, value);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, value,
+ brightnessMode);
}
if ((mask & KEYBOARD_BRIGHT_BIT) != 0) {
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, value);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, value,
+ brightnessMode);
}
}
@@ -1986,8 +2000,11 @@
startAnimation = true;
}
} else {
+ int brightnessMode = (mAutoBrightessEnabled
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
- lcdValue);
+ lcdValue, brightnessMode);
}
}
if (ANIMATE_BUTTON_LIGHTS) {
@@ -1997,8 +2014,11 @@
startAnimation = true;
}
} else {
+ int brightnessMode = (mUseSoftwareAutoBrightness
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
- buttonValue);
+ buttonValue, brightnessMode);
}
if (ANIMATE_KEYBOARD_LIGHTS) {
if (mKeyboardBrightness.setTargetLocked(keyboardValue,
@@ -2007,8 +2027,11 @@
startAnimation = true;
}
} else {
+ int brightnessMode = (mUseSoftwareAutoBrightness
+ ? HardwareService.BRIGHTNESS_MODE_SENSOR
+ : HardwareService.BRIGHTNESS_MODE_USER);
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
- keyboardValue);
+ keyboardValue, brightnessMode);
}
if (startAnimation) {
if (mDebugLightSensor) {
@@ -2329,10 +2352,12 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
// Don't let applications turn the screen all the way off
brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, brightness);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, brightness,
+ HardwareService.BRIGHTNESS_MODE_USER);
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
- (mKeyboardVisible ? brightness : 0));
- mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, brightness);
+ (mKeyboardVisible ? brightness : 0), HardwareService.BRIGHTNESS_MODE_USER);
+ mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, brightness,
+ HardwareService.BRIGHTNESS_MODE_USER);
long identity = Binder.clearCallingIdentity();
try {
mBatteryStats.noteScreenBrightness(brightness);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 69f4b89..327cd72 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -435,6 +435,7 @@
float mLastWallpaperY = -1;
float mLastWallpaperXStep = -1;
float mLastWallpaperYStep = -1;
+ boolean mSendingPointersToWallpaper = false;
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
WindowState mWaitingOnWallpaper;
@@ -1749,8 +1750,20 @@
}
try {
MotionEvent ev = MotionEvent.obtainNoHistory(pointer);
- ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left,
- srcWin.mFrame.top-wallpaper.mFrame.top);
+ if (srcWin != null) {
+ ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left,
+ srcWin.mFrame.top-wallpaper.mFrame.top);
+ } else {
+ ev.offsetLocation(-wallpaper.mFrame.left, -wallpaper.mFrame.top);
+ }
+ switch (pointer.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mSendingPointersToWallpaper = true;
+ break;
+ case MotionEvent.ACTION_UP:
+ mSendingPointersToWallpaper = false;
+ break;
+ }
wallpaper.mClient.dispatchPointer(ev, eventTime, false);
} catch (RemoteException e) {
Log.w(TAG, "Failure sending pointer to wallpaper", e);
@@ -4836,6 +4849,12 @@
if (action != MotionEvent.ACTION_MOVE) {
Log.w(TAG, "No window to dispatch pointer action " + ev.getAction());
}
+ synchronized (mWindowMap) {
+ if (mSendingPointersToWallpaper) {
+ Log.i(TAG, "Sending skipped pointer to wallpaper!");
+ sendPointerToWallpaperLocked(null, ev, ev.getEventTime());
+ }
+ }
if (qev != null) {
mQueue.recycleEvent(qev);
}
@@ -4843,6 +4862,12 @@
return INJECT_FAILED;
}
if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
+ synchronized (mWindowMap) {
+ if (mSendingPointersToWallpaper) {
+ Log.i(TAG, "Sending skipped pointer to wallpaper!");
+ sendPointerToWallpaperLocked(null, ev, ev.getEventTime());
+ }
+ }
if (qev != null) {
mQueue.recycleEvent(qev);
}
@@ -4963,6 +4988,19 @@
}
synchronized(mWindowMap) {
+ if (!target.isVisibleLw()) {
+ // During this motion dispatch, the target window has become
+ // invisible.
+ if (mSendingPointersToWallpaper) {
+ sendPointerToWallpaperLocked(null, ev, eventTime);
+ }
+ if (qev != null) {
+ mQueue.recycleEvent(qev);
+ }
+ ev.recycle();
+ return INJECT_SUCCEEDED;
+ }
+
if (qev != null && action == MotionEvent.ACTION_MOVE) {
mKeyWaiter.bindTargetWindowLocked(target,
KeyWaiter.RETURN_PENDING_POINTER, qev);
@@ -4987,15 +5025,16 @@
mKeyWaiter.mOutsideTouchTargets = null;
}
}
- final Rect frame = target.mFrame;
- ev.offsetLocation(-(float)frame.left, -(float)frame.top);
- mKeyWaiter.bindTargetWindowLocked(target);
// If we are on top of the wallpaper, then the wallpaper also
// gets to see this movement.
- if (mWallpaperTarget == target) {
- sendPointerToWallpaperLocked(target, ev, eventTime);
+ if (mWallpaperTarget == target || mSendingPointersToWallpaper) {
+ sendPointerToWallpaperLocked(null, ev, eventTime);
}
+
+ final Rect frame = target.mFrame;
+ ev.offsetLocation(-(float)frame.left, -(float)frame.top);
+ mKeyWaiter.bindTargetWindowLocked(target);
}
}
@@ -5918,12 +5957,12 @@
res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
}
}
- }
-
- if (res != null && returnWhat == RETURN_PENDING_POINTER) {
- synchronized (mWindowMap) {
- if (mWallpaperTarget == win) {
- sendPointerToWallpaperLocked(win, res, res.getEventTime());
+
+ if (res != null && returnWhat == RETURN_PENDING_POINTER) {
+ synchronized (mWindowMap) {
+ if (mWallpaperTarget == win || mSendingPointersToWallpaper) {
+ sendPointerToWallpaperLocked(win, res, res.getEventTime());
+ }
}
}
}
diff --git a/services/jni/com_android_server_HardwareService.cpp b/services/jni/com_android_server_HardwareService.cpp
index 22d4bd8..253e655 100644
--- a/services/jni/com_android_server_HardwareService.cpp
+++ b/services/jni/com_android_server_HardwareService.cpp
@@ -101,7 +101,7 @@
}
static void setLight_native(JNIEnv *env, jobject clazz, int ptr,
- int light, int colorARGB, int flashMode, int onMS, int offMS)
+ int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode)
{
Devices* devices = (Devices*)ptr;
light_state_t state;
@@ -115,6 +115,7 @@
state.flashMode = flashMode;
state.flashOnMS = onMS;
state.flashOffMS = offMS;
+ state.brightnessMode = brightnessMode;
devices->lights[light]->set_light(devices->lights[light], &state);
}
@@ -134,7 +135,7 @@
static JNINativeMethod method_table[] = {
{ "init_native", "()I", (void*)init_native },
{ "finalize_native", "(I)V", (void*)finalize_native },
- { "setLight_native", "(IIIIII)V", (void*)setLight_native },
+ { "setLight_native", "(IIIIIII)V", (void*)setLight_native },
{ "vibratorOn", "(J)V", (void*)vibratorOn },
{ "vibratorOff", "()V", (void*)vibratorOff }
};