summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/accounts/AccountManager.java142
-rw-r--r--core/java/android/app/ListActivity.java2
-rw-r--r--core/java/android/content/ContentProvider.java179
-rw-r--r--core/java/android/content/SyncOperation.java2
-rw-r--r--core/java/android/content/res/ColorStateList.java4
-rw-r--r--core/java/android/database/sqlite/SQLiteOpenHelper.java39
-rw-r--r--core/java/android/os/IPowerManager.aidl1
-rw-r--r--core/java/android/widget/BaseExpandableListAdapter.java4
-rw-r--r--core/java/android/widget/HeterogeneousExpandableList.java27
-rw-r--r--core/java/android/widget/Scroller.java6
-rw-r--r--core/tests/coretests/AndroidManifest.xml2
-rw-r--r--core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java440
12 files changed, 689 insertions, 159 deletions
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index b0adaec..fd3a0d0 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -45,26 +45,26 @@ import com.google.android.collect.Maps;
/**
* This class provides access to a centralized registry of the user's
- * online accounts. With this service, users only need to enter their
- * credentials (username and password) once for any account, granting
- * applications access to online resources with "one-click" approval.
+ * online accounts. The user enters credentials (username and password) once
+ * per account, granting applications access to online resources with
+ * "one-click" approval.
*
* <p>Different online services have different ways of handling accounts and
* authentication, so the account manager uses pluggable <em>authenticator</em>
- * modules for different <em>account types</em>. The authenticators (which
- * may be written by third parties) handle the actual details of validating
- * account credentials and storing account information. For example, Google,
- * Facebook, and Microsoft Exchange each have their own authenticator.
+ * modules for different <em>account types</em>. Authenticators (which may be
+ * written by third parties) handle the actual details of validating account
+ * credentials and storing account information. For example, Google, Facebook,
+ * and Microsoft Exchange each have their own authenticator.
*
* <p>Many servers support some notion of an <em>authentication token</em>,
* which can be used to authenticate a request to the server without sending
* the user's actual password. (Auth tokens are normally created with a
* separate request which does include the user's credentials.) AccountManager
- * can generate these auth tokens for applications, so the application doesn't
- * need to handle passwords directly. Auth tokens are normally reusable, and
- * cached by AccountManager, but must be refreshed periodically. It's the
- * responsibility of applications to <em>invalidate</em> auth tokens when they
- * stop working so the AccountManager knows it needs to regenerate them.
+ * can generate auth tokens for applications, so the application doesn't need to
+ * handle passwords directly. Auth tokens are normally reusable and cached by
+ * AccountManager, but must be refreshed periodically. It's the responsibility
+ * of applications to <em>invalidate</em> auth tokens when they stop working so
+ * the AccountManager knows it needs to regenerate them.
*
* <p>Applications accessing a server normally go through these steps:
*
@@ -84,14 +84,19 @@ import com.google.android.collect.Maps;
* {@link #addAccount} may be called to prompt the user to create an
* account of the appropriate type.
*
+ * <li><b>Important:</b> If the application is using a previously remembered
+ * account selection, it must make sure the account is still in the list
+ * of accounts returned by {@link #getAccountsByType}. Requesting an auth token
+ * for an account no longer on the device results in an undefined failure.
+ *
* <li>Request an auth token for the selected account(s) using one of the
* {@link #getAuthToken} methods or related helpers. Refer to the description
* of each method for exact usage and error handling details.
*
* <li>Make the request using the auth token. The form of the auth token,
* the format of the request, and the protocol used are all specific to the
- * service you are accessing. The application makes the request itself, using
- * whatever network and protocol libraries are useful.
+ * service you are accessing. The application may use whatever network and
+ * protocol libraries are useful.
*
* <li><b>Important:</b> If the request fails with an authentication error,
* it could be that a cached auth token is stale and no longer honored by
@@ -103,7 +108,7 @@ import com.google.android.collect.Maps;
* appropriate actions taken.
* </ul>
*
- * <p>Some AccountManager methods may require interaction with the user to
+ * <p>Some AccountManager methods may need to interact with the user to
* prompt for credentials, present options, or ask the user to add an account.
* The caller may choose whether to allow AccountManager to directly launch the
* necessary user interface and wait for the user, or to return an Intent which
@@ -113,18 +118,17 @@ import com.google.android.collect.Maps;
* the current foreground {@link Activity} context.
*
* <p>Many AccountManager methods take {@link AccountManagerCallback} and
- * {@link Handler} as parameters. These methods return immediately but
+ * {@link Handler} as parameters. These methods return immediately and
* run asynchronously. If a callback is provided then
* {@link AccountManagerCallback#run} will be invoked on the Handler's
* thread when the request completes, successfully or not.
- * An {@link AccountManagerFuture} is returned by these requests and also
- * supplied to the callback (if any). The result is retrieved by calling
- * {@link AccountManagerFuture#getResult()} which waits for the operation
- * to complete (if necessary) and either returns the result or throws an
- * exception if an error occurred during the operation.
- * To make the request synchronously, call
+ * The result is retrieved by calling {@link AccountManagerFuture#getResult()}
+ * on the {@link AccountManagerFuture} returned by the method (and also passed
+ * to the callback). This method waits for the operation to complete (if
+ * necessary) and either returns the result or throws an exception if an error
+ * occurred during the operation. To make the request synchronously, call
* {@link AccountManagerFuture#getResult()} immediately on receiving the
- * future from the method. No callback need be supplied.
+ * future from the method; no callback need be supplied.
*
* <p>Requests which may block, including
* {@link AccountManagerFuture#getResult()}, must never be called on
@@ -143,32 +147,32 @@ public class AccountManager {
public static final int ERROR_CODE_BAD_REQUEST = 8;
/**
- * The Bundle key used for the {@link String} account name in results
+ * Bundle key used for the {@link String} account name in results
* from methods which return information about a particular account.
*/
public static final String KEY_ACCOUNT_NAME = "authAccount";
/**
- * The Bundle key used for the {@link String} account type in results
+ * Bundle key used for the {@link String} account type in results
* from methods which return information about a particular account.
*/
public static final String KEY_ACCOUNT_TYPE = "accountType";
/**
- * The Bundle key used for the auth token value in results
+ * Bundle key used for the auth token value in results
* from {@link #getAuthToken} and friends.
*/
public static final String KEY_AUTHTOKEN = "authtoken";
/**
- * The Bundle key used for an {@link Intent} in results from methods that
+ * Bundle key used for an {@link Intent} in results from methods that
* may require the caller to interact with the user. The Intent can
* be used to start the corresponding user interface activity.
*/
public static final String KEY_INTENT = "intent";
/**
- * The Bundle key used to supply the password directly in options to
+ * Bundle key used to supply the password directly in options to
* {@link #confirmCredentials}, rather than prompting the user with
* the standard password prompt.
*/
@@ -476,7 +480,7 @@ public class AccountManager {
* @param account The {@link Account} to add
* @param password The password to associate with the account, null for none
* @param userdata String values to use for the account's userdata, null for none
- * @return Whether the account was successfully added. False if the account
+ * @return True if the account was successfully added, false if the account
* already exists, the account is null, or another error occurs.
*/
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
@@ -733,15 +737,14 @@ public class AccountManager {
* sense to ask the user directly for a password.
*
* <p>If a previously generated auth token is cached for this account and
- * type, then it will be returned. Otherwise, if we have a saved password
- * the server accepts, it will be used to generate a new auth token.
- * Otherwise, the user will be asked for a password, which will be sent to
- * the server to generate a new auth token.
+ * type, then it is returned. Otherwise, if a saved password is
+ * available, it is sent to the server to generate a new auth token.
+ * Otherwise, the user is prompted to enter a password.
*
- * <p>The value of the auth token type depends on the authenticator.
- * Some services use different tokens to access different functionality --
- * for example, Google uses different auth tokens to access Gmail and
- * Google Calendar for the same account.
+ * <p>Some authenticators have auth token <em>types</em>, whose value
+ * is authenticator-dependent. Some services use different token types to
+ * access different functionality -- for example, Google uses different auth
+ * tokens to access Gmail and Google Calendar for the same account.
*
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
@@ -778,6 +781,9 @@ public class AccountManager {
* <li> {@link IOException} if the authenticator experienced an I/O problem
* creating a new auth token, usually because of network trouble
* </ul>
+ * If the account is no longer present on the device, the return value is
+ * authenticator-dependent. The caller should verify the validity of the
+ * account before requesting an auth token.
*/
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
@@ -800,29 +806,27 @@ public class AccountManager {
* user should not be immediately interrupted with a password prompt.
*
* <p>If a previously generated auth token is cached for this account and
- * type, then it will be returned. Otherwise, if we have saved credentials
- * the server accepts, it will be used to generate a new auth token.
- * Otherwise, an Intent will be returned which, when started, will prompt
- * the user for a password. If the notifyAuthFailure parameter is set,
- * the same Intent will be associated with a status bar notification,
+ * type, then it is returned. Otherwise, if a saved password is
+ * available, it is sent to the server to generate a new auth token.
+ * Otherwise, an {@link Intent} is returned which, when started, will
+ * prompt the user for a password. If the notifyAuthFailure parameter is
+ * set, a status bar notification is also created with the same Intent,
* alerting the user that they need to enter a password at some point.
*
- * <p>If the intent is left in a notification, you will need to wait until
- * the user gets around to entering a password before trying again,
- * which could be hours or days or never. When it does happen, the
- * account manager will broadcast the {@link #LOGIN_ACCOUNTS_CHANGED_ACTION}
- * {@link Intent}, which applications can use to trigger another attempt
- * to fetch an auth token.
+ * <p>In that case, you may need to wait until the user responds, which
+ * could take hours or days or forever. When the user does respond and
+ * supply a new password, the account manager will broadcast the
+ * {@link #LOGIN_ACCOUNTS_CHANGED_ACTION} Intent, which applications can
+ * use to try again.
*
- * <p>If notifications are not enabled, it is the application's
- * responsibility to launch the returned intent at some point to let
- * the user enter credentials. In either case, the result from this
- * call will not wait for user action.
+ * <p>If notifyAuthFailure is not set, it is the application's
+ * responsibility to launch the returned Intent at some point.
+ * Either way, the result from this call will not wait for user action.
*
- * <p>The value of the auth token type depends on the authenticator.
- * Some services use different tokens to access different functionality --
- * for example, Google uses different auth tokens to access Gmail and
- * Google Calendar for the same account.
+ * <p>Some authenticators have auth token <em>types</em>, whose value
+ * is authenticator-dependent. Some services use different token types to
+ * access different functionality -- for example, Google uses different auth
+ * tokens to access Gmail and Google Calendar for the same account.
*
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
@@ -851,7 +855,7 @@ public class AccountManager {
* must enter credentials, the returned Bundle contains only
* {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
*
- * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
* <li> {@link OperationCanceledException} if the operation is canceled for
@@ -859,6 +863,9 @@ public class AccountManager {
* <li> {@link IOException} if the authenticator experienced an I/O problem
* creating a new auth token, usually because of network trouble
* </ul>
+ * If the account is no longer present on the device, the return value is
+ * authenticator-dependent. The caller should verify the validity of the
+ * account before requesting an auth token.
*/
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final boolean notifyAuthFailure,
@@ -910,9 +917,8 @@ public class AccountManager {
*
* If no activity was specified, the returned Bundle contains only
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
- * actual account creation process.
- *
- * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * actual account creation process. If an error occurred,
+ * {@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if no authenticator was registered for
* this account type or the authenticator failed to respond
@@ -979,9 +985,8 @@ public class AccountManager {
*
* If no activity or password was specified, the returned Bundle contains
* only {@link #KEY_INTENT} with the {@link Intent} needed to launch the
- * password prompt.
- *
- * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * password prompt. If an error occurred,
+ * {@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
* <li> {@link OperationCanceledException} if the operation was canceled for
@@ -1040,9 +1045,8 @@ public class AccountManager {
*
* If no activity was specified, the returned Bundle contains only
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
- * password prompt.
- *
- * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * password prompt. If an error occurred,
+ * {@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
* <li> {@link OperationCanceledException} if the operation was canceled for
@@ -1091,8 +1095,8 @@ public class AccountManager {
* which is empty if properties were edited successfully, or
* if no activity was specified, contains only {@link #KEY_INTENT}
* needed to launch the authenticator's settings dialog.
- *
- * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * If an error occurred, {@link AccountManagerFuture#getResult()}
+ * throws:
* <ul>
* <li> {@link AuthenticatorException} if no authenticator was registered for
* this account type or the authenticator failed to respond
@@ -1617,7 +1621,7 @@ public class AccountManager {
* <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
* </ul>
*
- * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * If an error occurred, {@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if no authenticator was registered for
* this account type or the authenticator failed to respond
diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java
index 84a57b5..0a80207 100644
--- a/core/java/android/app/ListActivity.java
+++ b/core/java/android/app/ListActivity.java
@@ -68,7 +68,7 @@ import android.widget.ListView;
* android:layout_weight=&quot;1&quot;
* android:drawSelectorOnTop=&quot;false&quot;/&gt;
*
- * &lt;TextView id=&quot;@id/android:empty&quot;
+ * &lt;TextView android:id=&quot;@id/android:empty&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;match_parent&quot;
* android:background=&quot;#FF0000&quot;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5fb2aae..9b9f796 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -57,6 +57,7 @@ import java.util.ArrayList;
*
* <p>The primary methods that need to be implemented are:
* <ul>
+ * <li>{@link #onCreate} which is called to initialize the provider</li>
* <li>{@link #query} which returns data to the caller</li>
* <li>{@link #insert} which inserts new data into the content provider</li>
* <li>{@link #update} which updates existing data in the content provider</li>
@@ -64,8 +65,15 @@ import java.util.ArrayList;
* <li>{@link #getType} which returns the MIME type of data in the content provider</li>
* </ul></p>
*
- * <p>This class takes care of cross process calls so subclasses don't have to worry about which
- * process a request is coming from.</p>
+ * <p class="caution">Data access methods (such as {@link #insert} and
+ * {@link #update}) may be called from many threads at once, and must be thread-safe.
+ * Other methods (such as {@link #onCreate}) are only called from the application
+ * main thread, and must avoid performing lengthy operations. See the method
+ * descriptions for their expected thread behavior.</p>
+ *
+ * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate
+ * ContentProvider instance, so subclasses don't have to worry about the details of
+ * cross-process calls.</p>
*/
public abstract class ContentProvider implements ComponentCallbacks {
/*
@@ -81,6 +89,21 @@ public abstract class ContentProvider implements ComponentCallbacks {
private Transport mTransport = new Transport();
+ /**
+ * Construct a ContentProvider instance. Content providers must be
+ * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared
+ * in the manifest</a>, accessed with {@link ContentResolver}, and created
+ * automatically by the system, so applications usually do not create
+ * ContentProvider instances directly.
+ *
+ * <p>At construction time, the object is uninitialized, and most fields and
+ * methods are unavailable. Subclasses should initialize themselves in
+ * {@link #onCreate}, not the constructor.
+ *
+ * <p>Content providers are created on the application main thread at
+ * application launch time. The constructor must not perform lengthy
+ * operations, or application startup will be delayed.
+ */
public ContentProvider() {
}
@@ -328,8 +351,8 @@ public abstract class ContentProvider implements ComponentCallbacks {
/**
- * Retrieve the Context this provider is running in. Only available once
- * onCreate(Map icicle) has been called -- this will be null in the
+ * Retrieves the Context this provider is running in. Only available once
+ * {@link #onCreate} has been called -- this will return null in the
* constructor.
*/
public final Context getContext() {
@@ -403,23 +426,59 @@ public abstract class ContentProvider implements ComponentCallbacks {
}
/**
- * Called when the provider is being started.
+ * Implement this to initialize your content provider on startup.
+ * This method is called for all registered content providers on the
+ * application main thread at application launch time. It must not perform
+ * lengthy operations, or application startup will be delayed.
+ *
+ * <p>You should defer nontrivial initialization (such as opening,
+ * upgrading, and scanning databases) until the content provider is used
+ * (via {@link #query}, {@link #insert}, etc). Deferred initialization
+ * keeps application startup fast, avoids unnecessary work if the provider
+ * turns out not to be needed, and stops database errors (such as a full
+ * disk) from halting application launch.
+ *
+ * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
+ * is a helpful utility class that makes it easy to manage databases,
+ * and will automatically defer opening until first use. If you do use
+ * SQLiteOpenHelper, make sure to avoid calling
+ * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
+ * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
+ * from this method. (Instead, override
+ * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
+ * database when it is first opened.)
*
* @return true if the provider was successfully loaded, false otherwise
*/
public abstract boolean onCreate();
+ /**
+ * {@inheritDoc}
+ * This method is always called on the application main thread, and must
+ * not perform lengthy operations.
+ *
+ * <p>The default content provider implementation does nothing.
+ * Override this method to take appropriate action.
+ * (Content providers do not usually care about things like screen
+ * orientation, but may want to know about locale changes.)
+ */
public void onConfigurationChanged(Configuration newConfig) {
}
-
+
+ /**
+ * {@inheritDoc}
+ * This method is always called on the application main thread, and must
+ * not perform lengthy operations.
+ *
+ * <p>The default content provider implementation does nothing.
+ * Subclasses may override this method to take appropriate action.
+ */
public void onLowMemory() {
}
/**
- * Receives a query request from a client in a local process, and
- * returns a Cursor. This is called internally by the {@link ContentResolver}.
- * This method can be called from multiple
- * threads, as described in
+ * Implement this to handle query requests from clients.
+ * This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
* <p>
@@ -476,11 +535,11 @@ public abstract class ContentProvider implements ComponentCallbacks {
String selection, String[] selectionArgs, String sortOrder);
/**
- * Return the MIME type of the data at the given URI. This should start with
+ * Implement this to handle requests for the MIME type of the data at the
+ * given URI. The returned MIME type should start with
* <code>vnd.android.cursor.item</code> for a single record,
* or <code>vnd.android.cursor.dir/</code> for multiple items.
- * This method can be called from multiple
- * threads, as described in
+ * This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
*
@@ -490,11 +549,10 @@ public abstract class ContentProvider implements ComponentCallbacks {
public abstract String getType(Uri uri);
/**
- * Implement this to insert a new row.
+ * Implement this to handle requests to insert a new row.
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
* after inserting.
- * This method can be called from multiple
- * threads, as described in
+ * This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
* @param uri The content:// URI of the insertion request.
@@ -504,12 +562,12 @@ public abstract class ContentProvider implements ComponentCallbacks {
public abstract Uri insert(Uri uri, ContentValues values);
/**
- * Implement this to insert a set of new rows, or the default implementation will
- * iterate over the values and call {@link #insert} on each of them.
+ * Override this to handle requests to insert a set of new rows, or the
+ * default implementation will iterate over the values and call
+ * {@link #insert} on each of them.
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
* after inserting.
- * This method can be called from multiple
- * threads, as described in
+ * This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
*
@@ -526,13 +584,12 @@ public abstract class ContentProvider implements ComponentCallbacks {
}
/**
- * A request to delete one or more rows. The selection clause is applied when performing
- * the deletion, allowing the operation to affect multiple rows in a
- * directory.
+ * Implement this to handle requests to delete one or more rows.
+ * The implementation should apply the selection clause when performing
+ * deletion, allowing the operation to affect multiple rows in a directory.
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
* after deleting.
- * This method can be called from multiple
- * threads, as described in
+ * This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
*
@@ -549,13 +606,12 @@ public abstract class ContentProvider implements ComponentCallbacks {
public abstract int delete(Uri uri, String selection, String[] selectionArgs);
/**
- * Update a content URI. All rows matching the optionally provided selection
- * will have their columns listed as the keys in the values map with the
- * values of those keys.
+ * Implement this to handle requests to update one or more rows.
+ * The implementation should update all rows matching the selection
+ * to set the columns according to the provided values map.
* As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
* after updating.
- * This method can be called from multiple
- * threads, as described in
+ * This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
*
@@ -570,18 +626,15 @@ public abstract class ContentProvider implements ComponentCallbacks {
String[] selectionArgs);
/**
- * Open a file blob associated with a content URI.
- * This method can be called from multiple
- * threads, as described in
+ * Override this to handle requests to open a file blob.
+ * The default implementation always throws {@link FileNotFoundException}.
+ * This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
* Processes and Threads</a>.
- *
- * <p>Returns a
- * ParcelFileDescriptor, from which you can obtain a
- * {@link java.io.FileDescriptor} for use with
- * {@link java.io.FileInputStream}, {@link java.io.FileOutputStream}, etc.
- * This can be used to store large data (such as an image) associated with
- * a particular piece of content.
+ *
+ * <p>This method returns a ParcelFileDescriptor, which is returned directly
+ * to the caller. This way large data (such as images and documents) can be
+ * returned without copying the content.
*
* <p>The returned ParcelFileDescriptor is owned by the caller, so it is
* their responsibility to close it when done. That is, the implementation
@@ -599,31 +652,35 @@ public abstract class ContentProvider implements ComponentCallbacks {
* no file associated with the given URI or the mode is invalid.
* @throws SecurityException Throws SecurityException if the caller does
* not have permission to access the file.
- *
+ *
* @see #openAssetFile(Uri, String)
* @see #openFileHelper(Uri, String)
- */
+ */
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
throw new FileNotFoundException("No files supported by provider at "
+ uri);
}
-
+
/**
* This is like {@link #openFile}, but can be implemented by providers
* that need to be able to return sub-sections of files, often assets
- * inside of their .apk. Note that when implementing this your clients
- * must be able to deal with such files, either directly with
- * {@link ContentResolver#openAssetFileDescriptor
- * ContentResolver.openAssetFileDescriptor}, or by using the higher-level
+ * inside of their .apk.
+ * This method can be called from multiple threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
+ *
+ * <p>If you implement this, your clients must be able to deal with such
+ * file slices, either directly with
+ * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
* {@link ContentResolver#openInputStream ContentResolver.openInputStream}
* or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
* methods.
- *
- * <p><em>Note: if you are implementing this to return a full file, you
+ *
+ * <p class="note">If you are implementing this to return a full file, you
* should create the AssetFileDescriptor with
* {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
- * applications that can not handle sub-sections of files.</em></p>
+ * applications that can not handle sub-sections of files.</p>
*
* @param uri The URI whose file is to be opened.
* @param mode Access mode for the file. May be "r" for read-only access,
@@ -735,17 +792,21 @@ public abstract class ContentProvider implements ComponentCallbacks {
}
/**
- * Applies each of the {@link ContentProviderOperation} objects and returns an array
- * of their results. Passes through OperationApplicationException, which may be thrown
- * by the call to {@link ContentProviderOperation#apply}.
- * If all the applications succeed then a {@link ContentProviderResult} array with the
- * same number of elements as the operations will be returned. It is implementation-specific
- * how many, if any, operations will have been successfully applied if a call to
- * apply results in a {@link OperationApplicationException}.
+ * Override this to handle requests to perform a batch of operations, or the
+ * default implementation will iterate over the operations and call
+ * {@link ContentProviderOperation#apply} on each of them.
+ * If all calls to {@link ContentProviderOperation#apply} succeed
+ * then a {@link ContentProviderResult} array with as many
+ * elements as there were operations will be returned. If any of the calls
+ * fail, it is up to the implementation how many of the others take effect.
+ * This method can be called from multiple threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+ * Processes and Threads</a>.
+ *
* @param operations the operations to apply
* @return the results of the applications
- * @throws OperationApplicationException thrown if an application fails.
- * See {@link ContentProviderOperation#apply} for more information.
+ * @throws OperationApplicationException thrown if any operation fails.
+ * @see ContentProviderOperation#apply
*/
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java
index a7d036f..b016088 100644
--- a/core/java/android/content/SyncOperation.java
+++ b/core/java/android/content/SyncOperation.java
@@ -90,7 +90,7 @@ public class SyncOperation implements Comparable {
private String toKey() {
StringBuilder sb = new StringBuilder();
sb.append("authority: ").append(authority);
- sb.append(" account: ").append(account);
+ sb.append(" account {name=" + account.name + ", type=" + account.type + "}");
sb.append(" extras: ");
extrasToStringBuilder(extras, sb, true /* asKey */);
return sb.toString();
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 70baaef..bd23db4 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -45,7 +45,6 @@ import java.util.Arrays;
* &lt;item android:state_focused="true" android:color="@color/testcolor1"/&gt;
* &lt;item android:state_pressed="true" android:state_enabled="false" android:color="@color/testcolor2" /&gt;
* &lt;item android:state_enabled="false" android:color="@color/testcolor3" /&gt;
- * &lt;item android:state_active="true" android:color="@color/testcolor4" /&gt;
* &lt;item android:color="@color/testcolor5"/&gt;
* &lt;/selector&gt;
* </pre>
@@ -56,6 +55,9 @@ import java.util.Arrays;
* An item with no state spec is considered to match any set of states and is generally useful as
* a final item to be used as a default. Note that if you have such an item before any other items
* in the list then any subsequent items will end up being ignored.
+ * <p>For more information, see the guide to <a
+ * href="{@docRoot}guide/topics/resources/color-list-resource.html">Color State
+ * List Resource</a>.</p>
*/
public class ColorStateList implements Parcelable {
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 52aac3a..47002b6 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -22,10 +22,16 @@ import android.util.Log;
/**
* A helper class to manage database creation and version management.
- * You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and
+ *
+ * <p>You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and
* optionally {@link #onOpen}, and this class takes care of opening the database
* if it exists, creating it if it does not, and upgrading it as necessary.
* Transactions are used to make sure the database is always in a sensible state.
+ *
+ * <p>This class makes it easy for {@link android.content.ContentProvider}
+ * implementations to defer opening and upgrading the database until first use,
+ * to avoid blocking application startup with long-running database upgrades.
+ *
* <p>For an example, see the NotePadProvider class in the NotePad sample application,
* in the <em>samples/</em> directory of the SDK.</p>
*/
@@ -42,8 +48,9 @@ public abstract class SQLiteOpenHelper {
/**
* Create a helper object to create, open, and/or manage a database.
- * The database is not actually created or opened until one of
- * {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
+ * This method always returns very quickly. The database is not actually
+ * created or opened until one of {@link #getWritableDatabase} or
+ * {@link #getReadableDatabase} is called.
*
* @param context to use to open or create the database
* @param name of the database file, or null for an in-memory database
@@ -62,13 +69,20 @@ public abstract class SQLiteOpenHelper {
/**
* Create and/or open a database that will be used for reading and writing.
- * Once opened successfully, the database is cached, so you can call this
- * method every time you need to write to the database. Make sure to call
- * {@link #close} when you no longer need it.
+ * The first time this is called, the database will be opened and
+ * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
+ * called.
*
- * <p>Errors such as bad permissions or a full disk may cause this operation
+ * <p>Once opened successfully, the database is cached, so you can
+ * call this method every time you need to write to the database.
+ * (Make sure to call {@link #close} when you no longer need the database.)
+ * Errors such as bad permissions or a full disk may cause this method
* to fail, but future attempts may succeed if the problem is fixed.</p>
*
+ * <p class="caution">Database upgrade may take a long time, you
+ * should not call this method from the application main thread, including
+ * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
+ *
* @throws SQLiteException if the database cannot be opened for writing
* @return a read/write database object valid until {@link #close} is called
*/
@@ -141,6 +155,11 @@ public abstract class SQLiteOpenHelper {
* database object will be closed and the read/write object will be returned
* in the future.
*
+ * <p class="caution">Like {@link #getWritableDatabase}, this method may
+ * take a long time to return, so you should not call it from the
+ * application main thread, including from
+ * {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
+ *
* @throws SQLiteException if the database cannot be opened
* @return a database object valid until {@link #getWritableDatabase}
* or {@link #close} is called.
@@ -219,9 +238,9 @@ public abstract class SQLiteOpenHelper {
public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
/**
- * Called when the database has been opened.
- * Override method should check {@link SQLiteDatabase#isReadOnly} before
- * updating the database.
+ * Called when the database has been opened. The implementation
+ * should check {@link SQLiteDatabase#isReadOnly} before updating the
+ * database.
*
* @param db The database.
*/
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 29aeb19..90ef1cb 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -26,6 +26,7 @@ interface IPowerManager
void releaseWakeLock(IBinder lock, int flags);
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);
+ void clearUserActivityTimeout(long now, long timeout);
void setPokeLock(int pokey, IBinder lock, String tag);
int getSupportedWakeLockFlags();
void setStayOnSetting(int val);
diff --git a/core/java/android/widget/BaseExpandableListAdapter.java b/core/java/android/widget/BaseExpandableListAdapter.java
index 396b7ae..b4d6ad7 100644
--- a/core/java/android/widget/BaseExpandableListAdapter.java
+++ b/core/java/android/widget/BaseExpandableListAdapter.java
@@ -43,14 +43,14 @@ public abstract class BaseExpandableListAdapter implements ExpandableListAdapter
}
/**
- * {@see DataSetObservable#notifyInvalidated()}
+ * @see DataSetObservable#notifyInvalidated()
*/
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
/**
- * {@see DataSetObservable#notifyChanged()}
+ * @see DataSetObservable#notifyChanged()
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
diff --git a/core/java/android/widget/HeterogeneousExpandableList.java b/core/java/android/widget/HeterogeneousExpandableList.java
index 1292733..e7e0933 100644
--- a/core/java/android/widget/HeterogeneousExpandableList.java
+++ b/core/java/android/widget/HeterogeneousExpandableList.java
@@ -23,12 +23,13 @@ import android.view.ViewGroup;
* Additional methods that when implemented make an
* {@link ExpandableListAdapter} take advantage of the {@link Adapter} view type
* mechanism.
- *
- * An {@link ExpandableListAdapter} declares one view type for its group items
+ * <p>
+ * An {@link ExpandableListAdapter} declares it has one view type for its group items
* and one view type for its child items. Although adapted for most {@link ExpandableListView}s,
- * these values should be tuned heterogeneous {@link ExpandableListView}s. Lists that contain
- * different types of group and/or child item views, should use an adapter that implements this
- * interface. This way, the recycled views that will be provided to
+ * these values should be tuned for heterogeneous {@link ExpandableListView}s.
+ * </p>
+ * Lists that contain different types of group and/or child item views, should use an adapter that
+ * implements this interface. This way, the recycled views that will be provided to
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* and
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
@@ -48,7 +49,7 @@ public interface HeterogeneousExpandableList {
* . Note: Integers must be in the range 0 to {@link #getGroupTypeCount} - 1.
* {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
* @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
- * @see getGroupTypeCount()
+ * @see #getGroupTypeCount()
*/
int getGroupType(int groupPosition);
@@ -65,7 +66,7 @@ public interface HeterogeneousExpandableList {
* Note: Integers must be in the range 0 to {@link #getChildTypeCount} - 1.
* {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
* @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
- * @see getChildTypeCount()
+ * @see #getChildTypeCount()
*/
int getChildType(int groupPosition, int childPosition);
@@ -78,13 +79,11 @@ public interface HeterogeneousExpandableList {
* . If the adapter always returns the same type of View for all group items, this method should
* return 1.
* </p>
- * <p>
* This method will only be called when the adapter is set on the {@link AdapterView}.
- * </p>
*
* @return The number of types of group Views that will be created by this adapter.
- * @see getChildTypeCount()
- * @see getGroupType()
+ * @see #getChildTypeCount()
+ * @see #getGroupType(int)
*/
int getGroupTypeCount();
@@ -97,13 +96,11 @@ public interface HeterogeneousExpandableList {
* , for any group. If the adapter always returns the same type of View for
* all child items, this method should return 1.
* </p>
- * <p>
* This method will only be called when the adapter is set on the {@link AdapterView}.
- * </p>
*
* @return The total number of types of child Views that will be created by this adapter.
- * @see getGroupTypeCount()
- * @see getChildType()
+ * @see #getGroupTypeCount()
+ * @see #getChildType(int, int)
*/
int getChildTypeCount();
}
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 784a75f..4cb0839 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -218,7 +218,11 @@ public class Scroller {
// Pin to mMinY <= mCurrY <= mMaxY
mCurrY = Math.min(mCurrY, mMaxY);
mCurrY = Math.max(mCurrY, mMinY);
-
+
+ if (mCurrX == mFinalX && mCurrY == mFinalY) {
+ mFinished = true;
+ }
+
break;
}
}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index a77717f..036da95 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -36,6 +36,8 @@
android:description="@string/permdesc_testDenied" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
new file mode 100644
index 0000000..0fe83e1
--- /dev/null
+++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.app.Instrumentation;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+public class BluetoothStressTest extends InstrumentationTestCase {
+ private static final String TAG = "BluetoothEnablerStressTest";
+
+ /**
+ * Timeout for {@link BluetoothAdapter#disable()} in ms.
+ */
+ private static final int DISABLE_TIMEOUT = 5000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#enable()} in ms.
+ */
+ private static final int ENABLE_TIMEOUT = 20000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#setScanMode(int)} in ms.
+ */
+ private static final int SET_SCAN_MODE_TIMEOUT = 5000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#startDiscovery()} in ms.
+ */
+ private static final int START_DISCOVERY_TIMEOUT = 5000;
+
+ /**
+ * Timeout for {@link BluetoothAdapter#cancelDiscovery()} in ms.
+ */
+ private static final int CANCEL_DISCOVERY_TIMEOUT = 5000;
+
+ private static final int DISCOVERY_STARTED_FLAG = 1;
+ private static final int DISCOVERY_FINISHED_FLAG = 1 << 1;
+ private static final int SCAN_MODE_NONE_FLAG = 1 << 2;
+ private static final int SCAN_MODE_CONNECTABLE_FLAG = 1 << 3;
+ private static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG = 1 << 4;
+ private static final int STATE_OFF_FLAG = 1 << 5;
+ private static final int STATE_TURNING_ON_FLAG = 1 << 6;
+ private static final int STATE_ON_FLAG = 1 << 7;
+ private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
+
+ /**
+ * Time between polls in ms.
+ */
+ private static final int POLL_TIME = 100;
+
+ private static final int ENABLE_ITERATIONS = 100;
+ private static final int DISCOVERABLE_ITERATIONS = 1000;
+ private static final int SCAN_ITERATIONS = 1000;
+
+ private Context mContext;
+
+ private Instrumentation mInstrumentation;
+
+ private class BluetoothReceiver extends BroadcastReceiver {
+ private int mFiredFlags = 0;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (this) {
+ if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
+ mFiredFlags |= DISCOVERY_STARTED_FLAG;
+ } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
+ mFiredFlags |= DISCOVERY_FINISHED_FLAG;
+ } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
+ int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
+ BluetoothAdapter.ERROR);
+ assertNotSame(mode, BluetoothAdapter.ERROR);
+ switch (mode) {
+ case BluetoothAdapter.SCAN_MODE_NONE:
+ mFiredFlags |= SCAN_MODE_NONE_FLAG;
+ break;
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
+ mFiredFlags |= SCAN_MODE_CONNECTABLE_FLAG;
+ break;
+ case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
+ mFiredFlags |= SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
+ break;
+ }
+ } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ BluetoothAdapter.ERROR);
+ assertNotSame(state, BluetoothAdapter.ERROR);
+ switch (state) {
+ case BluetoothAdapter.STATE_OFF:
+ mFiredFlags |= STATE_OFF_FLAG;
+ break;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ mFiredFlags |= STATE_TURNING_ON_FLAG;
+ break;
+ case BluetoothAdapter.STATE_ON:
+ mFiredFlags |= STATE_ON_FLAG;
+ break;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ mFiredFlags |= STATE_TURNING_OFF_FLAG;
+ break;
+ }
+ }
+ }
+ }
+
+ public int getFiredFlags() {
+ synchronized (this) {
+ return mFiredFlags;
+ }
+ }
+
+ public void resetFiredFlags() {
+ synchronized (this) {
+ mFiredFlags = 0;
+ }
+ }
+ }
+
+ private BluetoothReceiver mReceiver = new BluetoothReceiver();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mInstrumentation = getInstrumentation();
+ mContext = mInstrumentation.getTargetContext();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
+ filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
+ filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+ filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ @LargeTest
+ public void testEnableDisable() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ for (int i = 0; i < ENABLE_ITERATIONS; i++) {
+ Log.i(TAG, "Enable iteration " + (i + 1) + " of " + ENABLE_ITERATIONS);
+ enable(adapter);
+ disable(adapter);
+ }
+ }
+
+ @LargeTest
+ public void testDiscoverable() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ enable(adapter);
+
+ for (int i = 0; i < DISCOVERABLE_ITERATIONS; i++) {
+ Log.i(TAG, "Discoverable iteration " + (i + 1) + " of " + DISCOVERABLE_ITERATIONS);
+ discoverable(adapter);
+ undiscoverable(adapter);
+ }
+
+ disable(adapter);
+ }
+
+ @LargeTest
+ public void testScan() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ enable(adapter);
+
+ for (int i = 0; i < SCAN_ITERATIONS; i++) {
+ Log.i(TAG, "Scan iteration " + (i + 1) + " of " + SCAN_ITERATIONS);
+ startScan(adapter);
+ stopScan(adapter);
+ }
+
+ disable(adapter);
+ }
+
+ private void disable(BluetoothAdapter adapter) {
+ int mask = STATE_TURNING_OFF_FLAG | STATE_OFF_FLAG | SCAN_MODE_NONE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ int state = adapter.getState();
+ switch (state) {
+ case BluetoothAdapter.STATE_OFF:
+ assertFalse(adapter.isEnabled());
+ return;
+ case BluetoothAdapter.STATE_ON:
+ assertTrue(adapter.isEnabled());
+ assertTrue(adapter.disable());
+ break;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ assertFalse(adapter.isEnabled());
+ assertTrue(adapter.disable());
+ break;
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ assertFalse(adapter.isEnabled());
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ default:
+ fail("disable() invalid state: " + state);
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < DISABLE_TIMEOUT) {
+ state = adapter.getState();
+ if (state == BluetoothAdapter.STATE_OFF) {
+ assertFalse(adapter.isEnabled());
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ return;
+ }
+ } else {
+ assertFalse(adapter.isEnabled());
+ assertEquals(BluetoothAdapter.STATE_TURNING_OFF, state);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail("disable() timeout: " +
+ "state=" + state + " (expected " + BluetoothAdapter.STATE_OFF + ") " +
+ "flags=" + firedFlags + " (expected " + mask + ")");
+ }
+
+ private void enable(BluetoothAdapter adapter) {
+ int mask = STATE_TURNING_ON_FLAG | STATE_ON_FLAG | SCAN_MODE_CONNECTABLE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ int state = adapter.getState();
+ switch (state) {
+ case BluetoothAdapter.STATE_ON:
+ assertTrue(adapter.isEnabled());
+ return;
+ case BluetoothAdapter.STATE_OFF:
+ case BluetoothAdapter.STATE_TURNING_OFF:
+ assertFalse(adapter.isEnabled());
+ assertTrue(adapter.enable());
+ break;
+ case BluetoothAdapter.STATE_TURNING_ON:
+ assertFalse(adapter.isEnabled());
+ mask = 0; // Don't check for received intents since we might have missed them.
+ break;
+ default:
+ fail("enable() invalid state: state=" + state);
+ }
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < ENABLE_TIMEOUT) {
+ state = adapter.getState();
+ if (state == BluetoothAdapter.STATE_ON) {
+ assertTrue(adapter.isEnabled());
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ return;
+ }
+ } else {
+ assertFalse(adapter.isEnabled());
+ assertEquals(BluetoothAdapter.STATE_TURNING_ON, state);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail("enable() timeout: " +
+ "state=" + state + " (expected " + BluetoothAdapter.STATE_OFF + ") " +
+ "flags=" + firedFlags + " (expected " + mask + ")");
+ }
+
+ private void discoverable(BluetoothAdapter adapter) {
+ int mask = SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("discoverable() bluetooth not enabled");
+ }
+
+ int scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+ return;
+ }
+
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < SET_SCAN_MODE_TIMEOUT) {
+ scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ return;
+ }
+ } else {
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail("discoverable() timeout: " +
+ "scanMode=" + scanMode + " (expected " +
+ BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE + ") " +
+ "flags=" + firedFlags + " (expected " + mask + ")");
+ }
+
+ private void undiscoverable(BluetoothAdapter adapter) {
+ int mask = SCAN_MODE_CONNECTABLE_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("undiscoverable(): bluetooth not enabled");
+ }
+
+ int scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
+ return;
+ }
+
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < SET_SCAN_MODE_TIMEOUT) {
+ scanMode = adapter.getScanMode();
+ if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
+ if ((mReceiver.getFiredFlags() & mask) == mask) {
+ mReceiver.resetFiredFlags();
+ return;
+ }
+ } else {
+ assertEquals(scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail("undiscoverable() timeout: " +
+ "scanMode=" + scanMode + " (expected " +
+ BluetoothAdapter.SCAN_MODE_CONNECTABLE + ") " +
+ "flags=" + firedFlags + " (expected " + mask + ")");
+ }
+
+ private void startScan(BluetoothAdapter adapter) {
+ int mask = DISCOVERY_STARTED_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("startScan(): bluetooth not enabled");
+ }
+
+ if (adapter.isDiscovering()) {
+ return;
+ }
+
+ assertTrue(adapter.startDiscovery());
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < START_DISCOVERY_TIMEOUT) {
+ if (adapter.isDiscovering() && ((mReceiver.getFiredFlags() & mask) == mask)) {
+ mReceiver.resetFiredFlags();
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail("startScan() timeout: " +
+ "isDiscovering=" + adapter.isDiscovering() + " " +
+ "flags=" + firedFlags + " (expected " + mask + ")");
+ }
+
+ private void stopScan(BluetoothAdapter adapter) {
+ int mask = DISCOVERY_FINISHED_FLAG;
+ mReceiver.resetFiredFlags();
+
+ if (!adapter.isEnabled()) {
+ fail("stopScan(): bluetooth not enabled");
+ }
+
+ if (!adapter.isDiscovering()) {
+ return;
+ }
+
+ // TODO: put assertTrue() around cancelDiscovery() once it starts
+ // returning true.
+ adapter.cancelDiscovery();
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < CANCEL_DISCOVERY_TIMEOUT) {
+ if (!adapter.isDiscovering() && ((mReceiver.getFiredFlags() & mask) == mask)) {
+ mReceiver.resetFiredFlags();
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = mReceiver.getFiredFlags();
+ mReceiver.resetFiredFlags();
+ fail("stopScan() timeout: " +
+ "isDiscovering=" + adapter.isDiscovering() + " " +
+ "flags=" + firedFlags + " (expected " + mask + ")");
+ }
+
+ private void sleep(long time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ }
+ }
+}