Merge "Move NMS to CONNECTIVITY_INTERNAL permission."
diff --git a/Android.mk b/Android.mk
index 371c370..83c4b5b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -398,6 +398,7 @@
-since ./frameworks/base/api/12.xml 12 \
-since ./frameworks/base/api/13.xml 13 \
-since ./frameworks/base/api/14.txt 14 \
+ -since ./frameworks/base/api/15.txt 15 \
-werror -hide 113 \
-overview $(LOCAL_PATH)/core/java/overview.html
@@ -444,6 +445,8 @@
resources/samples/JetBoy "JetBoy" \
-samplecode $(sample_dir)/LunarLander \
resources/samples/LunarLander "Lunar Lander" \
+ -samplecode $(sample_dir)/training/ads-and-ux \
+ resources/samples/training/ads-and-ux "Mobile Advertisement Integration" \
-samplecode $(sample_dir)/MultiResolution \
resources/samples/MultiResolution "Multiple Resolutions" \
-samplecode $(sample_dir)/NFCDemo \
@@ -499,7 +502,10 @@
-samplecode $(sample_dir)/XmlAdapters \
resources/samples/XmlAdapters "XML Adapters" \
-samplecode $(sample_dir)/TtsEngine \
- resources/samples/TtsEngine "Text To Speech Engine"
+ resources/samples/TtsEngine "Text To Speech Engine" \
+ -samplecode $(sample_dir)/training/device-management-policy \
+ resources/samples/training/device-management-policy "Device Management Policy"
+
## SDK version identifiers used in the published docs
# major[.minor] version for current SDK. (full releases only)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4e5598b..e3b1f54 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2318,7 +2318,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2330,7 +2330,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2342,7 +2342,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2354,7 +2354,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2366,7 +2366,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2379,7 +2379,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2391,7 +2391,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2403,7 +2403,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -2416,7 +2416,7 @@
* <p>NOTE: This should not be used as the primary key of an Intent,
* since it will not result in the app launching with the correct
* action and category. Instead, use this with
- * {@link #makeMainSelectorActivity(String, String) to generate a main
+ * {@link #makeMainSelectorActivity(String, String)} to generate a main
* Intent with this category in the selector.</p>
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 4f19010..d38b8da 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1889,8 +1889,7 @@
if (cs != null) {
dr = cs.newDrawable(this);
} else {
- if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
- value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ if (isColorDrawable) {
dr = new ColorDrawable(value.data);
}
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index a73067a..9fe0bed 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -113,7 +113,7 @@
/*package*/ final String[] mTechStringList;
/*package*/ final Bundle[] mTechExtras;
/*package*/ final int mServiceHandle; // for use by NFC service, 0 indicates a mock
- /*package*/ final INfcTag mTagService;
+ /*package*/ final INfcTag mTagService; // interface to NFC service, will be null if mock tag
/*package*/ int mConnectedTechnology;
@@ -148,7 +148,7 @@
* @hide
*/
public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) {
- // set serviceHandle to 0 to indicate mock tag
+ // set serviceHandle to 0 and tagService to null to indicate mock tag
return new Tag(id, techList, techListExtras, 0, null);
}
@@ -266,6 +266,9 @@
throw new IllegalStateException("Close connection to the technology first!");
}
+ if (mTagService == null) {
+ throw new IOException("Mock tags don't support this operation.");
+ }
try {
Tag newTag = mTagService.rediscover(getServiceHandle());
if (newTag != null) {
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index b266bb6..226e079 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -259,6 +259,9 @@
try {
INfcTag tagService = mTag.getTagService();
+ if (tagService == null) {
+ throw new IOException("Mock tags don't support this operation.");
+ }
int serviceHandle = mTag.getServiceHandle();
if (tagService.isNdef(serviceHandle)) {
NdefMessage msg = tagService.ndefRead(serviceHandle);
@@ -303,6 +306,9 @@
try {
INfcTag tagService = mTag.getTagService();
+ if (tagService == null) {
+ throw new IOException("Mock tags don't support this operation.");
+ }
int serviceHandle = mTag.getServiceHandle();
if (tagService.isNdef(serviceHandle)) {
int errorCode = tagService.ndefWrite(serviceHandle, msg);
@@ -335,6 +341,9 @@
*/
public boolean canMakeReadOnly() {
INfcTag tagService = mTag.getTagService();
+ if (tagService == null) {
+ return false;
+ }
try {
return tagService.canMakeReadOnly(mNdefType);
} catch (RemoteException e) {
@@ -366,6 +375,9 @@
try {
INfcTag tagService = mTag.getTagService();
+ if (tagService == null) {
+ return false;
+ }
if (tagService.isNdef(mTag.getServiceHandle())) {
int errorCode = tagService.ndefMakeReadOnly(mTag.getServiceHandle());
switch (errorCode) {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index c25ebb7..24569fa 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -337,13 +337,16 @@
try {
res = onTransact(code, data, reply, flags);
} catch (RemoteException e) {
+ reply.setDataPosition(0);
reply.writeException(e);
res = true;
} catch (RuntimeException e) {
+ reply.setDataPosition(0);
reply.writeException(e);
res = true;
} catch (OutOfMemoryError e) {
RuntimeException re = new RuntimeException("Out of memory", e);
+ reply.setDataPosition(0);
reply.writeException(re);
res = true;
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ac8693d..b1e1132 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2571,7 +2571,8 @@
if (text != null) {
if (text.startsWith(SCHEME_TEL)) {
result.setType(HitTestResult.PHONE_TYPE);
- result.setExtra(text.substring(SCHEME_TEL.length()));
+ result.setExtra(URLDecoder.decode(text
+ .substring(SCHEME_TEL.length())));
} else if (text.startsWith(SCHEME_MAILTO)) {
result.setType(HitTestResult.EMAIL_TYPE);
result.setExtra(text.substring(SCHEME_MAILTO.length()));
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 84e7432..2573aa6d 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -106,7 +106,7 @@
#define AUDIOTRACK_ERROR_BAD_VALUE -2
#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
-#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
+#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
diff --git a/docs/html/guide/appendix/api-levels.jd b/docs/html/guide/appendix/api-levels.jd
index 95542bc..6ace709 100644
--- a/docs/html/guide/appendix/api-levels.jd
+++ b/docs/html/guide/appendix/api-levels.jd
@@ -83,8 +83,14 @@
<table>
<tr><th>Platform Version</th><th>API Level</th><th>VERSION_CODE</th><th>Notes</th></tr>
-
- <tr><td><a href="{@docRoot}sdk/android-4.0.html">Android 4.0</a></td>
+
+ <tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td>
+ <td><a href="{@docRoot}sdk/api_diff/15/changes.html" title="Diff Report">15</a></td>
+ <td>{@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1}</td>
+ <td><a href="{@docRoot}sdk/android-4.0-highlights.html">Platform
+Highlights</a></td></tr>
+
+ <tr><td><a href="{@docRoot}sdk/android-4.0.html">Android 4.0, 4.0.1, 4.0.2</a></td>
<td><a href="{@docRoot}sdk/api_diff/14/changes.html" title="Diff Report">14</a></td>
<td>{@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}</td>
<td><a href="{@docRoot}sdk/android-4.0-highlights.html">Platform
diff --git a/docs/html/images/training/ads-close-to-button.png b/docs/html/images/training/ads-close-to-button.png
new file mode 100755
index 0000000..fcb65aa
--- /dev/null
+++ b/docs/html/images/training/ads-close-to-button.png
Binary files differ
diff --git a/docs/html/images/training/ads-cover-content.png b/docs/html/images/training/ads-cover-content.png
new file mode 100755
index 0000000..f284d65
--- /dev/null
+++ b/docs/html/images/training/ads-cover-content.png
Binary files differ
diff --git a/docs/html/images/training/ads-eclipse-build-path.png b/docs/html/images/training/ads-eclipse-build-path.png
new file mode 100755
index 0000000..fe720fd
--- /dev/null
+++ b/docs/html/images/training/ads-eclipse-build-path.png
Binary files differ
diff --git a/docs/html/images/training/ads-top-banner.png b/docs/html/images/training/ads-top-banner.png
new file mode 100755
index 0000000..8dffe8d
--- /dev/null
+++ b/docs/html/images/training/ads-top-banner.png
Binary files differ
diff --git a/docs/html/images/training/device-mgmt-activate-device-admin.png b/docs/html/images/training/device-mgmt-activate-device-admin.png
new file mode 100755
index 0000000..1be1831
--- /dev/null
+++ b/docs/html/images/training/device-mgmt-activate-device-admin.png
Binary files differ
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
index d96bfde7..226ff9e 100644
--- a/docs/html/resources/resources-data.js
+++ b/docs/html/resources/resources-data.js
@@ -508,6 +508,16 @@
}
},
{
+ tags: ['sample', 'new'],
+ path: 'samples/training/device-management-policy/index.html',
+ title: {
+ en: 'Device Policy Management'
+ },
+ description: {
+ en: 'This is a security-aware sample application that demonstrates the enforcement of device administration policies on Android 2.2 or above platforms.'
+ }
+ },
+ {
tags: ['sample'],
path: 'samples/Home/index.html',
title: {
@@ -548,6 +558,16 @@
}
},
{
+ tags: ['sample', 'new'],
+ path: 'samples/training/ads-and-ux/index.html',
+ title: {
+ en: 'Mobile Advertisement Integration'
+ },
+ description: {
+ en: 'This sample demonstrates the integration of a mobile ad SDK with your application.'
+ }
+ },
+ {
tags: ['sample', 'ui', 'bestpractice', 'layout'],
path: 'samples/MultiResolution/index.html',
title: {
diff --git a/docs/html/sdk/android-4.0-highlights.jd b/docs/html/sdk/android-4.0-highlights.jd
index c1162d4..922bb08 100644
--- a/docs/html/sdk/android-4.0-highlights.jd
+++ b/docs/html/sdk/android-4.0-highlights.jd
@@ -298,7 +298,7 @@
linked together and integrated for easy accessibility. At the center is a new
<strong>People app</strong> that offers richer profile information, including a
large profile picture, phone numbers, addresses and accounts, status updates,
-events, and a new button for connecting on integrated social networks. </p>
+events, stream items, and a new button for connecting on integrated social networks. </p>
<p>The user's own contact information is stored in a new <strong>"Me"
profile</strong>, allowing easier sharing with apps and people. All of the
@@ -562,7 +562,7 @@
instant sharing of files, photos, or other media; streaming video or audio from
another device; or connecting to compatible printers or other devices.</p>
-<p>Android 4.0 also introduces built-in support for connecting to <strong>Bluetooth Health Device Profile (HDP)</strong> devices. With support from third-party apps, users can connect to wireless medical devices and sensors in hospitals, fitness centers, homes, and elsewhere. In addition, for connecting to higher quality Bluetooth audio devices, Android 4.0 adds support for Bluetooth Hands Free Profile (HFP) 1.6.</p>
+<p>Android 4.0 also introduces built-in support for connecting to <strong>Bluetooth Health Device Profile (HDP)</strong> devices. With support from third-party apps, users can connect to wireless medical devices and sensors in hospitals, fitness centers, homes, and elsewhere.</p>
<h2 id="DeveloperApis" style="clear:right">New Developer Features</h2>
@@ -633,21 +633,21 @@
<h3 id="communication-dev">Communication and sharing</h3>
<p>Android 4.0 extends social and sharing features to any application on the
-device. Applications can integrate contacts, profile data, and calendar events
-from any of the user’s activities or social networks.</p>
+device. Applications can integrate contacts, profile data, stream items,
+and calendar events from any of the user’s activities or social networks.</p>
<p style="margin-top:1em;margin-bottom:.75em;"><strong>Social API</strong></p>
<p>A shared social provider and API provide a new unified store for contacts,
-profile data, status updates, and photos. Any app or social network with user
+profile data, stream items, and photos. Any app or social network with user
permission can contribute raw contacts and make them accessible to other apps
and networks. Applications with user permission can also read profile data from
the provider and display it in their applications.</p>
<p>The social API lets applications store standard contact data as well as new
-types of content for any given contact, including large profile photos and
-recent activity feedback. Recent activity feedback is a standard way for
+types of content for any given contact, including large profile photos, stream
+items, and recent activity feedback. Recent activity feedback is a standard way for
applications to “tag” a contact with common activity, such as when the user
calls the contact or sends an email or SMS message. The social provider uses the
recent activity feedback as a new signal in ranking, such as for name
diff --git a/docs/html/sdk/android-4.0.3.jd b/docs/html/sdk/android-4.0.3.jd
new file mode 100644
index 0000000..68257cd
--- /dev/null
+++ b/docs/html/sdk/android-4.0.3.jd
@@ -0,0 +1,513 @@
+page.title=Android 4.0.3 Platform
+sdk.platform.version=4.0.3
+sdk.platform.apiLevel=15
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+ <li><a href="#relnotes">Revisions</a></li>
+ <li><a href="#api">API Overview</a></li>
+ <li><a href="#Honeycomb">Previous APIs</a></li>
+ <li><a href="#api-level">API Level</a></li>
+ <li><a href="#apps">Built-in Applications</a></li>
+ <li><a href="#locs">Locales</a></li>
+ <li><a href="#skins">Emulator Skins</a></li>
+</ol>
+
+<h2>Reference</h2>
+<ol>
+<li><a
+href="{@docRoot}sdk/api_diff/14/changes.html">API
+Differences Report »</a> </li>
+</ol>
+
+</div>
+</div>
+
+<p><em>API Level:</em> <strong>{@sdkPlatformApiLevel}</strong></p>
+
+<p>Android {@sdkPlatformVersion} is an incremental release of the Android 4.x
+(Ice Cream Sandwich) platform family. This release includes new features for
+users and developers, API changes, and various bug fixes.</p>
+
+<p>For developers, the Android {@sdkPlatformVersion} platform is available as a
+downloadable component for the Android SDK. The development platform includes a
+fully compliant Android library and system image as well as a set of emulator
+skins, sample applications, and more. The downloadable platform includes no
+external libraries.</p>
+
+<p>To start developing or testing against Android {@sdkPlatformVersion},
+use the Android SDK Manager to download the platform into your SDK. For more
+information, see <a href="{@docRoot}sdk/adding-components.html">Adding SDK
+Components</a>. If you are new to Android, <a
+href="{@docRoot}sdk/index.html">download the SDK Starter Package</a> first.</p>
+
+<p>For a high-level overview of the new user and developer features, see the
+<a href="http://developer.android.com/sdk/android-4.0-highlights.html">Platform
+Highlights</a>.</p>
+
+
+<h2 id="relnotes">Development Platform Revisions</h2>
+
+<p>The sections below provide notes about successive revisions of the Android
+{@sdkPlatformVersion} development platform for the Android SDK, as denoted by
+revision number. To determine what revisions you have installed in your SDK
+environment, refer to the "Installed Packages" listing in the Android SDK
+Manager.</p>
+
+
+<div class="toggle-content opened" style="padding-left:1em;">
+
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />
+ Android {@sdkPlatformVersion}, Revision 1</a> <em>(December 2011)</em>
+ </a></p>
+
+ <div class="toggle-content-toggleme" style="padding-left:2em;">
+
+<dl>
+<dt>Initial release. SDK Tools r14 or higher is required.
+ <p class="caution"><strong>Important:</strong> To download the new Android
+ 4.x system components from the Android SDK Manager, you must first update the
+ SDK tools to revision 14 or later and restart the Android SDK Manager. If you do not,
+ the Android 4.0 system components will not be available for download.</p>
+</dt>
+</dl>
+
+ </div>
+</div>
+
+
+<h2 id="api">API Overview</h2>
+
+<p>The sections below provide a technical overview of new APIs in Android 4.0.3.</p>
+
+<div class="toggle-content closed" style="padding-left:1em;">
+
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png"
+class="toggle-content-img" alt="" />
+ <strong>Table of Contents</strong>
+ </a></p>
+
+ <div class="toggle-content-toggleme" style="padding-left:2em;">
+ <ol class="toc" style="margin-left:-1em">
+ <li><a href="#contacts">Social stream API in contacts provider</a></li>
+ <li><a href="#calendar">Calendar provider</a></li>
+ <li><a href="#widgets">Home screen widgets</a></li>
+ <li><a href="#textservices">Spell-checking</a></li>
+ <li><a href="#bluetooth">Bluetooth</a></li>
+ <li><a href="#ui">UI toolkit</a></li>
+ <li><a href="#accessibility">Accessibility</a></li>
+ <li><a href="#tts">Text-to-speech</a></li>
+ <li><a href="#database">Database</a></li>
+ <li><a href="#intents">Intents</a></li>
+ <li><a href="#camera">Camera</a></li>
+ <li><a href="#permissions">Permissions</a></li>
+ </ol>
+ </div>
+</div>
+
+
+
+
+
+<h3 id="contacts">Social stream API in Contacts provider</h3>
+
+<p>Applications that use social stream data such as status updates and check-ins
+can now sync that data with each of the user’s contacts, providing items in a
+stream along with photos for each.</p>
+
+<p>The database table that contains an individual contact’s social stream is
+defined by {@link android.provider.ContactsContract.StreamItems}, the Uri for
+which is nested within the {@link android.provider.ContactsContract.RawContacts}
+directory to which the stream items belong. Each social stream table includes
+several columns for metadata about each stream item, such as an icon
+representing the source (an avatar), a label for the item, the primary text
+content, comments about the item (such as responses from other people), and
+more. Photos associated with a stream are stored in another table, defined by
+{@link android.provider.ContactsContract.StreamItemPhotos}, which is available
+as a sub-directory of the {@link android.provider.ContactsContract.StreamItems}
+Uri.</p>
+
+<p>See {@link android.provider.ContactsContract.StreamItems} and
+{@link android.provider.ContactsContract.StreamItemPhotos} for more information.</p>
+
+<p>To read or write social stream items for a contact, an application must
+request permission from the user by declaring <code><uses-permission
+android:name="android.permission.READ_SOCIAL_STREAM"></code> and/or <code><uses-permission
+android:name="android.permission.WRITE_SOCIAL_STREAM"></code> in their manifest files.</p>
+
+<h3 id="calendar">Calendar provider</h4>
+<ul>
+<li>Adds the class {@link android.provider.CalendarContract.Colors} to represent
+a color table in the Calendar provider. The class provivdes fields for accessing
+colors available for a given account. Colors are referenced by
+{@link android.provider.CalendarContract.ColorsColumns#COLOR_KEY COLOR_KEY}
+which must be unique for a given account name/type. These values can only be
+updated by the sync adapter.</li>
+<li>Adds {@link android.provider.CalendarContract.CalendarColumns#ALLOWED_AVAILABILITY ALLOWED_AVAILABILITY}
+and
+{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_ATTENDEE_TYPES ALLOWED_ATTENDEE_TYPES}
+for exchange/sync support.</li>
+<li>Adds {@link android.provider.CalendarContract.AttendeesColumns#TYPE_RESOURCE}
+(such as conference rooms) for attendees and
+{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY_TENTATIVE},
+as well as {@link android.provider.CalendarContract.EventsColumns#EVENT_COLOR_KEY}
+for events.</li>
+</ul>
+
+<h3 id="widgets">Home screen widgets</h3>
+
+<p>Starting from Android 4.0, home screen widgets should no longer include their
+own padding. Instead, the system now automatically adds padding for each widget,
+based the characteristics of the current screen. This leads to a more uniform,
+consistent presentation of widgets in a grid. To assist applications that host
+home screen widgets, the platform provides a new method
+{@link android.appwidget.AppWidgetHostView#getDefaultPaddingForWidget(android.content.Context, android.content.ComponentName, android.graphics.Rect)
+getDefaultPaddingForWidget()}. Applications can call this method to get the
+system-defined padding and account for it when computing the number of cells to
+allocate to the widget.</p>
+
+<h3 id="textservices">Spell-checking</h3>
+
+<ul>
+<li>For apps that accessing spell-checker services, a new {@link
+android.view.textservice.SpellCheckerSession#cancel() cancel()} method cancels
+any pending and running spell-checker tasks in a session.</li>
+
+<li>For spell-checker services, a new suggestions flag,
+{@link android.view.textservice.SuggestionsInfo#RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS},
+lets the services distinguish higher-confidence suggestions from
+lower-confidence ones. For example, a spell-checker could set the flag if an
+input word is not in the user dictionary but has likely suggestions, or not set
+the flag if an input word is not in the dictionary and has suggestions that are
+likely to be less useful.
+
+<p>Apps connected to the spell-checker can use the {@link
+android.view.textservice.SuggestionsInfo#RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS}
+flag in combination with other suggestion attributes, as well as the {@link
+android.view.textservice.SuggestionsInfo#getSuggestionsAttributes()} and {@link
+android.view.textservice.SuggestionsInfo#getSuggestionsCount()} methods, to
+determine whether to mark input words as typos and offer suggestions.</p></li>
+
+<li>A new {@link android.text.style.SuggestionSpan#FLAG_AUTO_CORRECTION} style
+for text spans indicates that auto correction is about to be applied to a
+word/text that the user is typing/composing. This type of suggestion is rendered
+differently, to indicate the auto correction is happening.</li>
+</ul>
+
+<h3 id="bluetooth">Bluetooth</h3>
+<p>New public methods {@link
+android.bluetooth.BluetoothDevice#fetchUuidsWithSdp()} and {@link
+android.bluetooth.BluetoothDevice#getUuids()} let apps determine the features
+(UUIDs) supported by a remote device. In the case of {@link
+android.bluetooth.BluetoothDevice#fetchUuidsWithSdp()}, the system performs a
+service discovery on the remote device to get the UUIDs supported, then
+broadcasts the result in an {@link
+android.bluetooth.BluetoothDevice#ACTION_UUID} intent.</p>
+
+<h3 id="ui">UI toolkit</h3>
+
+<p>New methods {@link android.app.Fragment#setUserVisibleHint(boolean) setUserVisibleHint()} and
+{@link android.app.Fragment#getUserVisibleHint() getUserVisibleHint()} allow a
+fragment to set a hint of whether or not it is currently user-visible. The
+system defers the start of fragments that are not user-visible until the loaders
+for visible fragments have run. The visibility hint is "true" by default.</li>
+</p>
+
+<h3 id="graphics">Graphics</h3>
+
+<ul>
+<li>New method {@link android.graphics.SurfaceTexture#setDefaultBufferSize(int
+width, int height)} in SurfaceTexture sets the default size of the image
+buffers. This method may be used to set the image size when producing images
+with {@link android.graphics.Canvas} (via {@link
+android.view.Surface#lockCanvas}), or OpenGL ES (via an EGLSurface).</li>
+<li>Adds definitions for the enums of the GL_OES_EGL_image_external OpenGL ES extension —
+{@link android.opengl.GLES11Ext#GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES},
+{@link android.opengl.GLES11Ext#GL_SAMPLER_EXTERNAL_OES},
+{@link android.opengl.GLES11Ext#GL_TEXTURE_BINDING_EXTERNAL_OES}, and
+{@link android.opengl.GLES11Ext#GL_TEXTURE_EXTERNAL_OES}.</li>
+</ul>
+
+<h3 id="accessibility">Accessibility</h3>
+
+<ul>
+<li>Clients of {@link android.widget.RemoteViews} can now use the method {@link
+android.widget.RemoteViews#setContentDescription(int, java.lang.CharSequence)
+setContentDescription()} to set and get the content description of any View in
+the inflated layout.</li>
+
+<li>The methods {@link android.view.accessibility.AccessibilityRecord#getMaxScrollX()},
+{@link android.view.accessibility.AccessibilityRecord#getMaxScrollY()},
+{@link android.view.accessibility.AccessibilityRecord#setMaxScrollX(int) setMaxScrollX()}, and
+{@link android.view.accessibility.AccessibilityRecord#setMaxScrollY(int) setMaxScrollY()}
+allow apps to get and set the maximum scroll offset for an
+{@link android.view.accessibility.AccessibilityRecord} object.</li>
+
+<li>When touch-exploration mode is enabled, a new secure setting
+{@link android.provider.Settings.Secure#ACCESSIBILITY_SPEAK_PASSWORD}
+indicates whether the user requests the IME to speak text entered in password fields, even when
+a headset is not in use. By default, no password text is spoken unless a headset
+is in use.</li>
+</ul>
+
+<h3 id="tts">Text-to-speech</h3>
+
+<ul>
+<li>Adds the new method {@link
+android.speech.tts.TextToSpeech.Engine#getFeatures(java.util.Locale)
+getFeatures()}for querying and enabling network TTS support.
+<li>Adds a new listener class, {@link
+android.speech.tts.UtteranceProgressListener}, that engines can register to
+receive notification of speech-sythesis errors.</li>
+</ul>
+
+<h3 id="database">Database</h3>
+
+<ul>
+<li>A new {@link android.database.CrossProcessCursorWrapper} class lets content
+providers return results for a cross-process query more effieciently. The new
+class is a useful building block for wrapping cursors that will be sent to
+processes remotely. It can also transform normal {@link android.database.Cursor}
+objects into {@link android.database.CrossProcessCursor} objects
+transparently.
+
+<p>The {@link android.database.CrossProcessCursorWrapper} class fixes common
+performance issues and bugs that applications have encountered when
+implementing content providers.</p></li>
+
+<li>The {@link android.database.CursorWindow#CursorWindow(java.lang.String)}
+constructor now takes a name string as input. The system no longer distinguishes
+between local and remote cursor windows, so {@link
+android.database.CursorWindow#CursorWindow(boolean)} is now deprecated.</li>
+</ul>
+
+<h3 id="intents">Intents</h3>
+
+<p>Adds for categories for targeting common types of applications on the
+device, such as {@link android.content.Intent#CATEGORY_APP_BROWSER}, {@link
+android.content.Intent#CATEGORY_APP_CALENDAR}, {@link
+android.content.Intent#CATEGORY_APP_MAPS}, and more.</li>
+
+<h3 id="camera">Camera</h3>
+
+<ul>
+<li>{@link android.media.MediaMetadataRetriever} adds the new constant
+{@link android.media.MediaMetadataRetriever#METADATA_KEY_LOCATION} to let apps
+access retrieve location information for an image or video. </li>
+
+<li>{@link android.media.CamcorderProfile} adds the QVGA (320x240) resolution
+profiles. Quality level is represented by the
+{@link android.media.CamcorderProfile#QUALITY_QVGA}.and
+{@link android.media.CamcorderProfile#QUALITY_TIME_LAPSE_QVGA} constants.</li>
+
+<li>New methods {@link android.hardware.Camera.Parameters#setVideoStabilization(boolean) setVideoStabilization()},
+{@link android.hardware.Camera.Parameters#getVideoStabilization() setVideoStabilization()}, and {android.hardware.Camera.Parameters#isVideoStabilizationSupported() isVideoStabilizationSupported()}
+let you check and manage video stabilization for a {@link android.hardware.Camera}.</li>
+</ul>
+
+<h3 id="Permissions">Permissions</h3>
+
+<p>The following are new permissions:</p>
+<ul>
+<li>{@link android.Manifest.permission#READ_SOCIAL_STREAM} and
+{@link android.Manifest.permission#WRITE_SOCIAL_STREAM}: Allow a sync
+adapter to read and write social stream data to a contact in the shared
+contacts provider.</li>
+</ul>
+
+
+<div class="special" style="margin-top:2em">
+<p>For a detailed view of all API changes in Android {@sdkPlatformVersion} (API Level
+{@sdkPlatformApiLevel}), see the <a
+href="{@docRoot}sdk/api_diff/{@sdkPlatformApiLevel}/changes.html">API Differences Report</a>.</p>
+</div>
+
+
+<h2 id="api-level">API Level</h2>
+
+<p>The Android {@sdkPlatformVersion} API is assigned an integer
+identifier—<strong>{@sdkPlatformApiLevel}</strong>—that is stored in the system itself.
+This identifier, called the "API level", allows the system to correctly determine whether an
+application is compatible with the system, prior to installing the application. </p>
+
+<p>To use APIs introduced in Android {@sdkPlatformVersion} in your application, you need compile the
+application against an Android platform that supports API level {@sdkPlatformApiLevel} or
+higher. Depending on your needs, you might also need to add an
+<code>android:minSdkVersion="{@sdkPlatformApiLevel}"</code> attribute to the
+<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code <uses-sdk>}</a>
+element.</p>
+
+<p>For more information, see the <a href="{@docRoot}guide/appendix/api-levels.html">API Levels</a>
+document. </p>
+
+
+<h2 id="apps">Built-in Applications</h2>
+
+<p>The system image included in the downloadable platform provides these
+built-in applications:</p>
+
+<table style="border:0;padding-bottom:0;margin-bottom:0;">
+<tr>
+<td style="border:0;padding-bottom:0;margin-bottom:0;">
+<ul>
+<li>API Demos</li>
+<li>Browser</li>
+<li>Calculator</li>
+<li>Calendar</li>
+<li>Camera</li>
+<li>Clock</li>
+<li>Custom Locale</li>
+<li>Dev Tools</li>
+<li>Downloads</li>
+<li>Email</li>
+<li>Gallery</li>
+</ul>
+</td>
+<td style="border:0;padding-bottom:0;margin-bottom:0;padding-left:5em;">
+<ul>
+<li>Gestures Builder</li>
+<li>Messaging</li>
+<li>Music</li>
+<li>People</li>
+<li>Phone</li>
+<li>Search</li>
+<li>Settings</li>
+<li>Speech Recorder</li>
+<li>Widget Preview</li>
+</ul>
+</td>
+</tr>
+</table>
+
+
+<h2 id="locs" style="margin-top:.75em;">Locales</h2>
+
+<p>The system image included in the downloadable SDK platform provides a variety of built-in
+locales. In some cases, region-specific strings are available for the locales. In other cases, a
+default version of the language is used. The languages that are available in the Android 3.0 system
+image are listed below (with <em>language</em>_<em>country/region</em> locale descriptor).</p>
+
+<table style="border:0;padding-bottom:0;margin-bottom:0;">
+<tr>
+<td style="border:0;padding-bottom:0;margin-bottom:0;">
+<ul>
+<li>Arabic, Egypt (ar_EG)</li>
+<li>Arabic, Israel (ar_IL)</li>
+<li>Bulgarian, Bulgaria (bg_BG)</li>
+<li>Catalan, Spain (ca_ES)</li>
+<li>Czech, Czech Republic (cs_CZ)</li>
+<li>Danish, Denmark(da_DK)</li>
+<li>German, Austria (de_AT)</li>
+<li>German, Switzerland (de_CH)</li>
+<li>German, Germany (de_DE)</li>
+<li>German, Liechtenstein (de_LI)</li>
+<li>Greek, Greece (el_GR)</li>
+<li>English, Australia (en_AU)</li>
+<li>English, Canada (en_CA)</li>
+<li>English, Britain (en_GB)</li>
+<li>English, Ireland (en_IE)</li>
+<li>English, India (en_IN)</li>
+<li>English, New Zealand (en_NZ)</li>
+<li>English, Singapore(en_SG)</li>
+<li>English, US (en_US)</li>
+<li>English, Zimbabwe (en_ZA)</li>
+<li>Spanish (es_ES)</li>
+<li>Spanish, US (es_US)</li>
+<li>Finnish, Finland (fi_FI)</li>
+<li>French, Belgium (fr_BE)</li>
+<li>French, Canada (fr_CA)</li>
+<li>French, Switzerland (fr_CH)</li>
+<li>French, France (fr_FR)</li>
+<li>Hebrew, Israel (he_IL)</li>
+<li>Hindi, India (hi_IN)</li>
+</ul>
+</td>
+<td style="border:0;padding-bottom:0;margin-bottom:0;padding-left:5em;">
+<li>Croatian, Croatia (hr_HR)</li>
+<li>Hungarian, Hungary (hu_HU)</li>
+<li>Indonesian, Indonesia (id_ID)</li>
+<li>Italian, Switzerland (it_CH)</li>
+<li>Italian, Italy (it_IT)</li>
+<li>Japanese (ja_JP)</li>
+<li>Korean (ko_KR)</li>
+<li>Lithuanian, Lithuania (lt_LT)</li>
+<li>Latvian, Latvia (lv_LV)</li>
+<li>Norwegian bokmål, Norway (nb_NO)</li>
+<li>Dutch, Belgium (nl_BE)</li>
+<li>Dutch, Netherlands (nl_NL)</li>
+<li>Polish (pl_PL)</li>
+<li>Portuguese, Brazil (pt_BR)</li>
+<li>Portuguese, Portugal (pt_PT)</li>
+<li>Romanian, Romania (ro_RO)</li>
+<li>Russian (ru_RU)</li></li>
+<li>Slovak, Slovakia (sk_SK)</li>
+<li>Slovenian, Slovenia (sl_SI)</li>
+<li>Serbian (sr_RS)</li>
+<li>Swedish, Sweden (sv_SE)</li>
+<li>Thai, Thailand (th_TH)</li>
+<li>Tagalog, Philippines (tl_PH)</li>
+<li>Turkish, Turkey (tr_TR)</li>
+<li>Ukrainian, Ukraine (uk_UA)</li>
+<li>Vietnamese, Vietnam (vi_VN)</li>
+<li>Chinese, PRC (zh_CN)</li>
+<li>Chinese, Taiwan (zh_TW)</li>
+</td>
+</tr>
+</table>
+
+<p class="note"><strong>Note:</strong> The Android platform may support more
+locales than are included in the SDK system image. All of the supported locales
+are available in the <a href="http://source.android.com/">Android Open Source
+Project</a>.</p>
+
+<h2 id="skins">Emulator Skins</h2>
+
+<p>The downloadable platform includes the following emulator skins:</p>
+
+<ul>
+ <li>
+ QVGA (240x320, low density, small screen)
+ </li>
+ <li>
+ WQVGA400 (240x400, low density, normal screen)
+ </li>
+ <li>
+ WQVGA432 (240x432, low density, normal screen)
+ </li>
+ <li>
+ HVGA (320x480, medium density, normal screen)
+ </li>
+ <li>
+ WVGA800 (480x800, high density, normal screen)
+ </li>
+ <li>
+ WVGA854 (480x854 high density, normal screen)
+ </li>
+ <li>
+ WXGA720 (1280x720, extra-high density, normal screen)
+ </li>
+ <li>
+ WSVGA (1024x600, medium density, large screen)
+ </li>
+ <li>
+ WXGA (1280x800, medium density, xlarge screen)
+ </li>
+</ul>
+
+<p>To test your application on an emulator that represents the latest Android device, you can create
+an AVD with the new WXGA720 skin (it's an xhdpi, normal screen device). Note that the emulator
+currently doesn't support the new on-screen navigation bar for devices without hardware navigation
+buttons, so when using this skin, you must use keyboard keys <em>Home</em> for the Home button,
+<em>ESC</em> for the Back button, and <em>F2</em> or <em>Page-up</em> for the Menu button.</p>
+
+<p>However, due to performance issues in the emulator when running high-resolution screens such as
+the one for the WXGA720 skin, we recommend that you primarily use the traditional WVGA800 skin
+(hdpi, normal screen) to test your application.</p>
+
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 791e7aa..f0651ea 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -76,11 +76,11 @@
</ul>
<ul>
<li class="toggle-list">
- <div><a href="<?cs var:toroot ?>sdk/android-4.0.html">
- <span class="en">Android 4.0 Platform</span></a> <span class="new">new!</span></div>
+ <div><a href="<?cs var:toroot ?>sdk/android-4.0-highlights.html">
+ <span class="en">Android 4.0.x Platform</span></a> <span class="new">new!</span></div>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/android-4.0-highlights.html">Platform Highlights</a></li>
- <li><a href="<?cs var:toroot ?>sdk/api_diff/14/changes.html">API Differences Report »</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/android-4.0.3.html">Android 4.0.3 Platform</a> <span class="new">new!</span></li>
+ <li><a href="<?cs var:toroot ?>sdk/android-4.0.html">Android 4.0 Platform</a> </li>
</ul>
</li>
<li class="toggle-list">
diff --git a/docs/html/shareables/training/DeviceManagement.zip b/docs/html/shareables/training/DeviceManagement.zip
new file mode 100644
index 0000000..9f7ec69
--- /dev/null
+++ b/docs/html/shareables/training/DeviceManagement.zip
Binary files differ
diff --git a/docs/html/shareables/training/MobileAds.zip b/docs/html/shareables/training/MobileAds.zip
new file mode 100644
index 0000000..468e4ee
--- /dev/null
+++ b/docs/html/shareables/training/MobileAds.zip
Binary files differ
diff --git a/docs/html/training/enterprise/device-management-policy.jd b/docs/html/training/enterprise/device-management-policy.jd
new file mode 100644
index 0000000..52f0e37
--- /dev/null
+++ b/docs/html/training/enterprise/device-management-policy.jd
@@ -0,0 +1,220 @@
+page.title=Enhancing Security with Device Management Policies
+parent.title=Developing Android Applications for the Enterprise
+parent.link=index.html
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#DeclarePolicy">Define and Declare Your Policy</a></li>
+ <li><a href="#CreateDeviceAdminReceiver">Create a Device Administration Receiver</a></li>
+ <li><a href="#ActivateDeviceAdmin">Activate the Device Administrator</a></li>
+ <li><a href="#ImplementDevicePolicyController">Implement the Device Policy Controller</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/DeviceManagement.zip"
+class="button">Download the sample</a>
+ <p class="filename">DeviceManagement.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p>Since Android 2.2 (API level 8), the Android platform offes system-level device management
+capabilities through the Device Administration APIs.</p>
+
+<p>In this lesson, you will learn how to create a security-aware application that manages access to
+its content by enforcing device management policies. Specifically, the application can be configured
+such that it ensures a screen-lock password of sufficient strength is set up before displaying
+restricted content to the user.</p>
+
+
+<h2 id="DeclarePolicy">Define and Declare Your Policy</h2>
+
+<p>First, you need to define the kinds of policy to support at the functional level. Policies may
+cover screen-lock password strength, expiration timeout, encryption, etc.</p>
+
+<p>You must declare the selected policy set, which will be enforced by the application, in the
+<code>res/xml/device_admin.xml</code> file. The Android manifest should also reference the
+declared policy set.</p>
+
+<p>Each declared policy corresponds to some number of related device policy methods in {@link
+android.app.admin.DevicePolicyManager} (defining minimum password length and minimum number of
+uppercase characters are two examples). If an application attempts to invoke methods whose
+corresponding policy is not declared in the XML, this will result in a {@link
+java.lang.SecurityException} at runtime. Other permissions,
+such as <code>force-lock</code>, are available if the application intends to manage
+other kinds of policy. As you'll see later, as part of the device administrator activation process,
+the list of declared policies will be presented to the user on a system screen.</p>
+
+<p>The following snippet declares the limit password policy in <code>res/xml/device_admin.xml</code>:</p>
+
+<pre>
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-policies>
+ <limit-password />
+ </uses-policies>
+</device-admin>
+</pre>
+
+<p>Policy declaration XML referenced in Android manifest:</p>
+
+<pre>
+<receiver android:name=".Policy$PolicyAdmin"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <strong><meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin" /></strong>
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+</receiver>
+</pre>
+
+
+<h2 id="CreateDeviceAdminReceiver">Create a Device Administration Receiver</h2>
+
+<p>Create a Device Administration broadcast receiver, which gets notified of events related to the policies you’ve declared to support. An application can selectively override callback methods.</p>
+
+<p>In the sample application, Device Admin, when the device administrator is deactivated by the
+user, the configured policy is erased from the shared preference. You should consider implementing
+business logic that is relevant to your use case. For example, the application might take some
+actions to mitigate security risk by implementing some combination of deleting sensitive data on the
+device, disabling remote synchronization, alerting an administrator, etc.</p>
+
+<p>For the broadcast receiver to work, be sure to register it in the Android manifest as illustrated in the above snippet.</p>
+
+<pre>
+public static class PolicyAdmin extends DeviceAdminReceiver {
+
+ @Override
+ public void onDisabled(Context context, Intent intent) {
+ // Called when the app is about to be deactivated as a device administrator.
+ // Deletes previously stored password policy.
+ super.onDisabled(context, intent);
+ SharedPreferences prefs = context.getSharedPreferences(APP_PREF, Activity.MODE_PRIVATE);
+ prefs.edit().clear().commit();
+ }
+}
+</pre>
+
+
+<h2 id="ActivateDeviceAdmin">Activate the Device Administrator</h2>
+
+<p>Before enforcing any policies, the user needs to manually activate the application as a device
+administrator. The snippet below illustrates how to trigger the settings activity in which the
+user can activate your application. It is good practice to include the explanatory text to highlight
+to users why the application is requesting to be a device administrator, by specifying the
+{@link android.app.admin.DevicePolicyManager#EXTRA_ADD_EXPLANATION} extra in the intent.</p>
+
+<div class="figure" style="width:220px">
+<img src="/images/training/device-mgmt-activate-device-admin.png" />
+<p class="img-caption"><strong>Figure 1.</strong> The user activation screen in which you can
+provide a description of your device policies.</p>
+</div>
+
+<pre>
+if (!mPolicy.isAdminActive()) {
+
+ Intent activateDeviceAdminIntent =
+ new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
+
+ activateDeviceAdminIntent.putExtra(
+ DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+ mPolicy.getPolicyAdmin());
+
+ // It is good practice to include the optional explanation text to
+ // explain to user why the application is requesting to be a device
+ // administrator. The system will display this message on the activation
+ // screen.
+ activateDeviceAdminIntent.putExtra(
+ DevicePolicyManager.EXTRA_ADD_EXPLANATION,
+ getResources().getString(R.string.device_admin_activation_message));
+
+ startActivityForResult(activateDeviceAdminIntent,
+ REQ_ACTIVATE_DEVICE_ADMIN);
+}
+</pre>
+
+<p>If the user chooses "Activate," the application becomes a device administrator and can begin
+configuring and enforcing the policy.</p>
+
+<p>The application also needs to be prepared to handle set back situations where the user abandons
+the activation process by hitting the Cancel button, the Back key, or the Home key. Therefore,
+{@link android.app.Activity#onResume onResume()} in the Policy Set Up Activity needs to have logic
+to reevaluate the condition and present the Device Administrator Activation option to the user if
+needed.</p>
+
+
+<h2 id="ImplementDevicePolicyController">Implement the Device Policy Controller</h2>
+
+<p>After the device administrator is activated successfully, the application then configures Device
+Policy Manager with the requested policy. Keep in mind that new policies are being added to
+Android with each release. It is appropriate to perform version checks in your application if using
+new policies while supporting older versions of the platform. For example, the Password Minimum
+Upper Case policy is only available with API level 11 (Honeycomb) and above. The following code
+demonstrates how you can check the version at runtime.</p>
+
+<pre>
+DevicePolicyManager mDPM = (DevicePolicyManager)
+ context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ComponentName mPolicyAdmin = new ComponentName(context, PolicyAdmin.class);
+...
+mDPM.setPasswordQuality(mPolicyAdmin, PASSWORD_QUALITY_VALUES[mPasswordQuality]);
+mDPM.setPasswordMinimumLength(mPolicyAdmin, mPasswordLength);
+if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ mDPM.setPasswordMinimumUpperCase(mPolicyAdmin, mPasswordMinUpperCase);
+}
+</pre>
+
+<p>At this point, the application is able to enforce the policy. While the application has no access
+to the actual screen-lock password used, through the Device Policy Manager API it can determine
+whether the existing password satisfies the required policy. If it turns out that the existing
+screen-lock password is not sufficient, the device administration API does not automatically take
+corrective action. It is the application’s responsibility to explicitly launch the system
+password-change screen in the Settings app. For example:</p>
+
+<pre>
+if (!mDPM.isActivePasswordSufficient()) {
+ ...
+ // Triggers password change screen in Settings.
+ Intent intent =
+ new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+ startActivity(intent);
+}
+</pre>
+
+<p>Normally, the user can select from one of the available lock mechanisms, such as None, Pattern,
+PIN (numeric), or Password (alphanumeric). When a password policy is configured, those password
+types that are weaker than those defined in the policy are disabled. For example, if the
+“Numeric” password quality is configured, the user can select either PIN (numeric) or Password
+(alphanumeric) password only.</p>
+
+<p>Once the device is properly secured by setting up a proper screen-lock password, the application
+allows access to the secured content.</p>
+
+<pre>
+if (!mDPM.isAdminActive(..)) {
+ // Activates device administrator.
+ ...
+} else if (!mDPM.isActivePasswordSufficient()) {
+ // Launches password set-up screen in Settings.
+ ...
+} else {
+ // Grants access to secure content.
+ ...
+ startActivity(new Intent(context, SecureActivity.class));
+}
+</pre>
diff --git a/docs/html/training/enterprise/index.jd b/docs/html/training/enterprise/index.jd
new file mode 100644
index 0000000..05bb29c
--- /dev/null
+++ b/docs/html/training/enterprise/index.jd
@@ -0,0 +1,51 @@
+page.title=Developing Android Applications for the Enterprise
+
+trainingnavtop=true
+startpage=true
+next.title=Enhancing Security with Device Management Policies
+next.link=device-management-policy.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 2.0 (API Level 5) or higher</li>
+ <li>Experience with <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media
+Playback</a></li>
+</ul>
+
+<!-- related docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/DeviceManagement.zip"
+class="button">Download the sample</a>
+ <p class="filename">DeviceManagement.zip</p>
+</div>
+
+</div>
+</div>
+
+
+<p>In this class, you'll learn APIs and techniques you can use when developing applications
+for the enterprise.</p>
+
+
+<h2>Lessons</h2>
+
+
+<dl>
+ <dt><b><a href="device-management-policy.html">Enhancing Security with Device Management
+Policies</a></b></dt>
+ <dd>In this lesson, you will learn how to create a security-aware application that manages
+access to its content by enforcing device management policies</dd>
+</dl>
diff --git a/docs/html/training/id-auth/authenticate.jd b/docs/html/training/id-auth/authenticate.jd
new file mode 100644
index 0000000..31352e7
--- /dev/null
+++ b/docs/html/training/id-auth/authenticate.jd
@@ -0,0 +1,253 @@
+page.title=Authenticating to OAuth2 Services
+parent.title=Identifying and Authenticating Users
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Identifying Your User
+previous.link=identify.html
+next.title=Creating a Custom Account Type
+next.link=custom_auth.html
+
+@jd:body
+
+ <!-- This is the training bar -->
+<div id="tb-wrapper">
+ <div id="tb">
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#Gather">Gather Information</a></li>
+ <li><a href="#RequestToken">Request an Auth Token</a></li>
+ <li><a href="#RequestAgain">Request an Auth Token... Again</a></li>
+ <li><a href="#ConnectToService">Connect to the Online Service</a></li>
+</ol>
+ </div>
+</div>
+
+<p>In order to securely access an online service, users need to authenticate to
+the service—they need to provide proof of their identity. For an
+application that accesses a third-party service, the security problem is even
+more complicated. Not only does the user need to be authenticated to access the
+service, but the application also needs to be authorized to act on the user's
+behalf. </p>
+
+<p>The industry standard way to deal with authentication to third-party services
+is the OAuth2 protocol. OAuth2 provides a single value, called an <strong>auth
+token</strong>, that represents both the user's identity and the application's
+authorization to act on the user's behalf. This lesson demonstrates connecting
+to a Google server that supports OAuth2. Although Google services are used as an
+example, the techniques demonstrated will work on any service that correctly
+supports the OAuth2 protocol.</p>
+
+<p>Using OAuth2 is good for:</p>
+<ul>
+<li>Getting permission from the user to access an online service using his or
+her account.</li>
+<li>Authenticating to an online service on behalf of the user.</li>
+<li>Handling authentication errors.</li>
+</ul>
+
+
+<h2 id="Gather">Gather Information</h2>
+
+<p>To begin using OAuth2, you need to know a few things about the API you're trying
+to access:</p>
+
+<ul>
+<li>The url of the service you want to access.</li>
+<li>The <strong>auth scope</strong>, which is a string that defines the specific
+type of access your app is asking for. For instance, the auth scope for
+read-only access to Google Tasks is <code>View your tasks</code>, while the auth
+scope for read-write access to Google Tasks is <code>Manage Your
+Tasks</code>.</li>
+<li>A <strong>client id</strong> and <strong>client secret</strong>, which are
+strings that identify your app to the service. You need to obtain these strings
+directly from the service owner. Google has a self-service system for obtaining
+client ids and secrets. The article <a
+href="http://code.google.com/apis/tasks/articles/oauth-and-tasks-on-android.
+html">Getting Started with the Tasks API and OAuth 2.0 on Android</a> explains
+how to use this system to obtain these values for use with the Google Tasks
+API.</li>
+</ul>
+
+
+<h2 id="RequestToken">Request an Auth Token</h2>
+
+<p>Now you're ready to request an auth token. Auth tokens usually expire after
+some period of time, so you'll have to renew them.</p>
+
+ <!-- TODO: I think a flowchart would be useful here, or perhaps a link to an as-yet-to-be-created
+flowchart that lives in the docs. -->
+
+<p>To get an auth token you first need to request the
+{@link android.Manifest.permission#ACCOUNT_MANAGER}
+to yourmanifest file. To actually do anything useful with the
+token, you'll also need to add the {@link android.Manifest.permission#INTERNET}
+permission.</p>
+
+<code>
+<manifest ... >
+ <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ ...
+</manifest>
+</code>
+
+
+<p>Once your app has these permissions set, you can call {@link
+android.accounts.AccountManager#getAuthToken AccountManager.getAuthToken()} to get the
+token.</p>
+
+<p>Watch out! Calling methods on {@link android.accounts.AccountManager} can be tricky! Since
+account operations may involve network communication, most of the {@link
+android.accounts.AccountManager} methods are asynchronous. This means that instead of doing all of
+your auth work in one function, you need to implement it as a series of callbacks. For example:</p>
+
+<pre>
+AccountManager am = AccountManager.get(this);
+Bundle options = new Bundle();
+
+am.getAuthToken(
+ myAccount_, // Account retrieved using getAccountsByType()
+ "Manage your tasks", // Auth scope
+ options, // Authenticator-specific options
+ this, // Your activity
+ new OnTokenAcquired(), // Callback called when a token is successfully acquired
+ new Handler(new OnError())); // Callback called if an error occurs
+</pre>
+
+<p>In this example, <code>OnTokenAcquired</code> is a class that extends
+{@link android.accounts.AccountManagerCallback}. {@link android.accounts.AccountManager} calls
+{@link android.accounts.AccountManagerCallback#run run()} on <code>OnTokenAcquired</code> with an
+{@link android.accounts.AccountManagerFuture} that contains a {@link android.os.Bundle}. If
+the call succeeded, the token is inside
+the {@link android.os.Bundle}.</p>
+
+<p>Here's how you can get the token from the {@link android.os.Bundle}:</p>
+
+<pre>
+private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
+ @Override
+ public void run(AccountManagerFuture<Bundle> result) {
+ // Get the result of the operation from the AccountManagerFuture.
+ Bundle bundle = result.getResult();
+
+ // The token is a named value in the bundle. The name of the value
+ // is stored in the constant AccountManager.KEY_AUTHTOKEN.
+ token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
+ ...
+ }
+}
+</pre>
+
+<p>If all goes well, the {@link android.os.Bundle} contains a valid token in the {@link
+android.accounts.AccountManager#KEY_AUTHTOKEN} key and you're off to the races. Things don't
+always go that smoothly, though...</p>
+
+
+<h2 id="RequestAgain">Request an Auth Token... Again</h2>
+
+<p>Your first request for an auth token might fail for several reasons:</p>
+
+<ul>
+<li>An error in the device or network caused {@link android.accounts.AccountManager} to fail.</li>
+<li>The user decided not to grant your app access to the account.</li>
+<li>The stored account credentials aren't sufficient to gain access to the account.</li>
+<li>The cached auth token has expired.</li>
+</ul>
+
+<p>Applications can handle the first two cases trivially, usually by simply
+showing an error message to the user. If the network is down or the user decided
+not to grant access, there's not much that your application can do about it. The
+last two cases are a little more complicated, because well-behaved applications
+are expected to handle these failures automatically.</p>
+
+<p>The third failure case, having insufficient credentials, is communicated via the {@link
+android.os.Bundle} you receive in your {@link android.accounts.AccountManagerCallback}
+(<code>OnTokenAcquired</code> from the previous example). If the {@link android.os.Bundle} includes
+an {@link android.content.Intent} in the {@link android.accounts.AccountManager#KEY_INTENT} key,
+then the authenticator is telling you that it needs to interact directly with the user before it can
+give you a valid token.</p>
+
+<p>There may be many reasons for the authenticator to return an {@link android.content.Intent}. It
+may be the first time the user has logged in to this account. Perhaps the user's account has expired
+and they need to log in again, or perhaps their stored credentials are incorrect. Maybe the account
+requires two-factor authentication or it needs to activate the camera to do a retina scan. It
+doesn't really matter what the reason is. If you want a valid token, you're going to have to fire
+off the {@link android.content.Intent} to get it.</p>
+
+<pre>
+private class OnTokenAcquired implements AccountManagerCallback<Bundle> {
+ @Override
+ public void run(AccountManagerFuture<Bundle> result) {
+ ...
+ Intent launch = (Intent) result.get(AccountManager.KEY_INTENT);
+ if (launch != null) {
+ startActivityForResult(launch, 0);
+ return;
+ }
+ }
+}
+</pre>
+
+<p>Note that the example uses {@link android.app.Activity#startActivityForResult
+startActivityForResult()}, so that you can capture
+the result of the {@link android.content.Intent} by implementing {@link
+android.app.Activity#onActivityResult onActivityResult()} in
+your own activity. This is important! If you don't capture the result from the
+authenticator's response {@link android.content.Intent},
+it's impossible to tell whether the user has successfully authenticated or not.
+If the result is {@link android.app.Activity#RESULT_OK}, then the
+authenticator has updated the stored credentials so that they are sufficient for
+the level of access you requested, and you should call {@link
+android.accounts.AccountManager#getAuthToken AccountManager.getAuthToken()} again to request the new
+auth token.</p>
+
+<p>The last case, where the token has expired, it is not actually an {@link
+android.accounts.AccountManager} failure. The only way to discover whether a token is expired or not
+is to contact the server, and it would be wasteful and expensive for {@link
+android.accounts.AccountManager} to continually go online to check the state of all of its tokens.
+So this is a failure that can only be detected when an application like yours tries to use the auth
+token to access an online service.</p>
+
+
+<h2 id="ConnectToService">Connect to the Online Service</h2>
+
+<p>The example below shows how to connect to a Google server. Since Google uses the
+industry standard OAuth2 protocol to
+authenticate requests, the techniques discussed here are broadly
+applicable. Keep in mind, though, that every
+server is different. You may find yourself needing to make minor adjustments to
+these instructions to account for your specific
+situation.</p>
+
+<p>The Google APIs require you to supply four values with each request: the API
+key, the client ID, the client secret,
+and the auth key. The first three come from the Google API Console
+website. The last is the string value you
+obtained by calling {@link android.accounts.AccountManager#getAuthToken(android.accounts.Account,java.lang.String,android.os.Bundle,android.app.Activity,android.accounts.AccountManagerCallback,android.os.Handler) AccountManager.getAuthToken()}. You pass these to the
+Google Server as part of
+an HTTP request.</p>
+
+<pre>
+URL url = new URL("https://www.googleapis.com/tasks/v1/users/@me/lists?key=" + <em>your_api_key</em>);
+URLConnection conn = (HttpURLConnection) url.openConnection();
+conn.addRequestProperty("client_id", <em>your client id</em>);
+conn.addRequestProperty("client_secret", <em>your client secret</em>);
+conn.setRequestProperty("Authorization", "OAuth " + token);
+</pre>
+
+<p>If the request returns
+an HTTP error code of 401, then your token has been denied. As mentioned in the
+last section, the most common reason for
+this is that the token has expired. The fix is
+simple: call
+{@link android.accounts.AccountManager#invalidateAuthToken AccountManager.invalidateAuthToken()} and
+repeat the token acquisition dance one
+more time.</p>
+
+<p>Because expired tokens are such a common occurrence, and fixing them is so easy, many
+applications just assume the token has expired before even asking for it. If renewing a token is a
+cheap operation for your server, you might prefer to call {@link
+android.accounts.AccountManager#invalidateAuthToken AccountManager.invalidateAuthToken()} before the
+first call to {@link android.accounts.AccountManager#getAuthToken AccountManager.getAuthToken()},
+and spare yourself the need to request an auth token twice.</p>
diff --git a/docs/html/training/id-auth/custom_auth.jd b/docs/html/training/id-auth/custom_auth.jd
new file mode 100644
index 0000000..4f59746
--- /dev/null
+++ b/docs/html/training/id-auth/custom_auth.jd
@@ -0,0 +1,185 @@
+page.title=Creating a Custom Account Type
+parent.title=Identifying and Authenticating Users
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Authenticating to OAuth2 Services
+previous.link=authenticate.html
+
+@jd:body
+
+<div id="tb-wrapper">
+ <div id="tb">
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#AccountCode">Implement Your Custom Account Code</a></li>
+ <li><a href="#Security">Be Smart About Security!</a></li>
+ <li><a href="#ExtendThatThing">Extend AbstractAccountAuthenticator</a></li>
+ <li><a href="#TaskFour">Create an Authenticator Service</a></li>
+ <li><a href="#DistributeService">Distribute Your Service</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a
+href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
+SampleSyncAdapter app</a></li>
+</ul>
+ </div>
+</div>
+
+<p>In the previous lessons, we've talked about using Google accounts to identify Google users and
+access Google APIs. But what if you've got your own online service? It turns out
+to be relatively straightforward to install new account types on a user's
+device. This lesson explains how to create a custom account type that works the
+same way as the built-in accounts do. </p>
+
+
+<h2 id="AccountCode">Implement Your Custom Account Code</h2>
+
+<p>The first thing you'll need is a way to get credentials from the user. This
+may be as simple as a dialog box that asks for a name and a password. Or it may
+be a more exotic procedure like a one-time password or a biometric scan. Either
+way, it's your responsibility to implement the code that:</p>
+<ol>
+ <li>Collects credentials from the user</li>
+ <li>Authenticates the credentials with the server</li>
+ <li>Stores the credentials on the device</li>
+</ol>
+
+
+<p>Typically all three of these requirements can be handled by one activity. We'll call this the
+authenticator activity.</p>
+
+<p>Because they need to interact with the {@link android.accounts.AccountManager} system,
+authenticator activities have certain requirements that normal activities don't. To make it easy to
+get things right, the Android framework supplies a base class, {@link
+android.accounts.AccountAuthenticatorActivity}, which you can extend to create your own custom
+authenticator.</p>
+
+<p>How you address the first two requirements of an authenticator activity,
+credential collection and authentication, is completely up to you. (If there
+were only one way to do it, there'd be no need for "custom" account types, after
+all.) The third requirement has a canonical, and rather simple,
+implementation:</p>
+
+<pre>
+final Account account = new Account(mUsername, <em>your_account_type</em>);
+mAccountManager.addAccountExplicitly(account, mPassword, null);
+</pre>
+
+
+<h2 id="Security">Be Smart About Security!</h2>
+
+<p>It's important to understand that {@link android.accounts.AccountManager} is not an encryption
+service
+or a keychain. It stores account credentials just as you pass them, in <strong>plain
+text</strong>. On most devices, this isn't
+a particular concern, because it stores them in
+a database that is only accessible to root. But on a rooted device, the
+credentials would be readable by anyone with {@code adb} access to the device.</p>
+
+<p>With this in mind, you shouldn't pass the user's actual
+password to {@link android.accounts.AccountManager#addAccountExplicitly
+AccountManager.addAccountExplicitly()}. Instead, you should store a
+cryptographically secure token that would be of limited use to an attacker. If your
+user credentials are protecting something valuable, you should carefully
+consider doing something similar.</p>
+
+<p class="caution"><strong>Remember:</strong> When it comes to security code, follow the
+"Mythbusters" rule: don't try this at home! Consult a security professional before implementing any
+custom account code.</p>
+
+<p>Now that the security disclaimers are out of the way, it's time to get back to work.
+You've already implemented the meat of your custom account code; what's left is
+plumbing.</p>
+
+
+<h2 id="ExtendThatThing">Extend AbstractAccountAuthenticator</h2>
+
+<p>In order for the {@link android.accounts.AccountManager} to work with your custom account
+code, you
+need a class that implements the interfaces that {@link android.accounts.AccountManager} expects.
+This class is the <em>authenticator class</em>.</p>
+
+<p>The easiest way to create an authenticator class is to extend
+{@link android.accounts.AbstractAccountAuthenticator} and implement its abstract methods. If you've
+worked through the previous lessons, the abstract methods of
+{@link android.accounts.AbstractAccountAuthenticator} should look familiar: they're the opposite
+side of
+the methods you called in the previous lesson to get account information and
+authorization tokens.</p>
+
+<p>Implementing an authenticator class properly requires a number of separate
+pieces of code. First, {@link android.accounts.AbstractAccountAuthenticator} has seven abstract
+methods that you must override. Second, you need to add an
+<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">intent filter</a> for
+<code>"android.accounts.AccountAuthenticator"</code> to your application
+manifest (shown in the next section). Finally, you must supply two XML resources that define, among
+other
+things, the name of your custom account type and the icon that the system will
+display next to accounts of this type.</p>
+
+<p> You can find a step-by-step guide to implementing a successful authenticator class and the XML
+files in the {@link android.accounts.AbstractAccountAuthenticator} documentation. There's also a
+sample implementation in the <a
+href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
+SampleSyncAdapter sample app</a>.</p>
+
+<p>As you read through the SampleSyncAdapter code, you'll notice that several of
+the methods return an intent in a bundle. This is the same intent that will be
+used to launch your custom authenticator activity. If your authenticator
+activity needs any special initialization parameters, you can attach them to the
+intent using {@link android.content.Intent#putExtra Intent.putExtra()}.</p>
+
+
+<h2 id="TaskFour">Create an Authenticator Service</h2>
+
+<p>Now that you have an authenticator class, you need a place for it to live.
+Account authenticators need to be available to multiple applications and work in
+the background, so naturally they're required to run inside a {@link android.app.Service}. We'll
+call this the authenticator service.</p>
+
+<p>Your authenticator service can be very simple. All it needs to do is create
+an instance of your authenticator class in {@link android.app.Service#onCreate onCreate()} and call
+{@link android.accounts.AbstractAccountAuthenticator#getIBinder getIBinder()} in {@link
+android.app.Service#onBind onBind()}. The <a
+href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
+SampleSyncAdapter</a> contains a good example of an authenticator service.</p>
+
+<p>Don't forget to add a {@code <service>} tag to your manifest file
+and add an intent filter for the AccountAuthenticator intent and declare the account
+authenticator:</p>
+
+<pre>
+<service ...>
+ <intent-filter>
+ <action android:name="android.accounts.AccountAuthenticator" />
+ </intent-filter>
+ <meta-data android:name="android.accounts.AccountAuthenticator"
+ android:resource="@xml/authenticator" />
+</service>
+</pre>
+
+
+<h2 id="DistributeService">Distribute Your Service</h2>
+
+<p>You're done! The system now recognizes your account type, right alongside all
+the big name account types like "Google" and "Corporate." You can use the
+<strong>Accounts & Sync</strong> Settings page to add an account, and apps that ask for
+accounts of your custom type will be able to enumerate and authenticate just as
+they would with any other account type.</p>
+
+<p>Of course, all of this assumes that your account service is actually
+installed on the device. If only one app will ever access the service, then
+this isn't a big deal—just bundle the service in the app.
+But if you want your account service to be used by more than one app, things get
+trickier. You don't want to bundle the service with all of your apps and have
+multiple copies of it taking up space on your user's device.</p>
+
+<p>One solution is to place the service in one small, special-purpose APK. When
+an app wishes to use your custom account type, it can check the device to see if
+your custom account service is available. If not, it can direct the user to
+Android Market to download the service. This may seem like a great deal of
+trouble at first, but compared with the alternative of re-entering credentials
+for every app that uses your custom account, it's refreshingly easy.</p>
diff --git a/docs/html/training/id-auth/identify.jd b/docs/html/training/id-auth/identify.jd
new file mode 100644
index 0000000..f18a34f
--- /dev/null
+++ b/docs/html/training/id-auth/identify.jd
@@ -0,0 +1,137 @@
+page.title=Identifying Your User
+parent.title=Identifying and Authenticating Users
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Authenticating to OAuth2 Services
+next.link=authenticate.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+ <div id="tb">
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#ForYou">Determine if AccountManager for You</a></li>
+ <li><a href="#TaskTwo">Decide What Type of Account to Use</a></li>
+ <li><a href="#GetPermission">Request GET_ACCOUNT permission</a></li>
+ <li><a href="#TaskFive">Query AccountManager for a List of Accounts</a></li>
+ <li><a href="#IdentifyUser">Use the Account Object to Identify the User</a></li>
+ <li><a href="#IdIsEnough">Decide Whether Identification is Enough</a></li>
+</ol>
+ </div>
+</div>
+
+
+<p>Everyone likes it when you remember their name. One of the simplest, most
+effective things you can do to make your app more lovable is to remember who
+your user is—especially when the user upgrades to a new device or starts carrying
+a tablet as well as a phone. But how do you know who your user is? And how do
+you recognize them on a new device?</p>
+
+<p>For many applications, the answer is the {@link android.accounts.AccountManager} APIs. With the
+user's permission, you can use Account Manager to uniquely identify a user
+by the online identity that the user has stored on their device.</p>
+
+<p>Integration with the user's accounts allows you to do a variety of things such as:</p>
+<ul>
+<li>Auto-fill forms with the user's email address.</li>
+<li>Retrieve an ID that is tied to a user, not the device.</li>
+</ul>
+
+
+<h2 id="ForYou">Determine if AccountManager for You</h2>
+
+<p>Applications typically identify the user in three different ways:</p>
+<ol type="a">
+<li>Ask the user to type in a username </li>
+<li>Use a unique device identifier rather than a user identifier</li>
+<li>Retrieve a built-in account from {@link android.accounts.AccountManager}</li>
+</ol>
+
+<p>Option (a) is problematic. First, asking the user to type something before
+entering your app will automatically make your app less appealing. Second,
+there's no guarantee that the username chosen will be unique. </p>
+
+<p>Option (b) is less onerous for the user, but it's
+<a href="http://android-developers.blogspot.com/2011/03/identifying-app-installations.html">tricky
+to get right</a>. More
+importantly, it only allows you to remember the user on one device. Imagine the
+frustration of someone who upgrades to a shiny new device, only to find that
+your app no longer remembers them.</p>
+
+<p>Option (c) is the preferred technique. Account Manager allows you to get
+information about the accounts that are stored on the user's device. As we'll
+see in this lesson, using Account Manager lets you identify your user, no matter
+how many devices the user may own, by adding just a couple of extra taps to your
+UI.</p>
+
+
+<h2 id="TaskTwo">Decide What Type of Account to Use</h2>
+
+<p>Android devices can store multiple accounts from many different providers.
+When you query {@link android.accounts.AccountManager} for account names, you can choose to filter
+by
+account type. The account type is a string that uniquely identifies the entity
+that issued the account. For instance, Google accounts have type "com.google,"
+while Twitter uses "com.twitter.android.auth.login."</p>
+
+
+<h2 id="GetPermission">Request GET_ACCOUNT permission</h2>
+
+<p>In order to get a list of accounts on the device, your app needs the {@link
+android.Manifest.permission#GET_ACCOUNTS}
+permission. Add a <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code
+<uses-permission>}</a> tag in your manifest file to request
+this permission:</p>
+
+<pre>
+<manifest ... >
+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+ ...
+</manifest>
+</pre>
+
+
+<h2 id="TaskFive">Query AccountManager for a List of Accounts</h2>
+
+<p>Once you decide what account type you're interested in, you need to query for accounts of that
+type. Get an instance of {@link android.accounts.AccountManager} by calling {@link
+android.accounts.AccountManager#get(android.content.Context) AccountManager.get()}. Then use that
+instance to call {@link android.accounts.AccountManager#getAccountsByType(java.lang.String)
+getAccountsByType()}.</p>
+
+<pre>
+AccountManager am = AccountManager.get(this); // "this" references the current Context
+
+Account[] accounts = am.getAccountsByType("com.google");
+</pre>
+
+<p>This returns an array of {@link android.accounts.Account} objects. If there's more than one
+{@link android.accounts.Account} in
+the array, you should present a dialog asking the user to select one.</p>
+
+
+<h2 id="IdentifyUser">Use the Account Object to Identify the User</h2>
+
+<p>The {@link android.accounts.Account} object contains an account name, which for Google accounts
+is an
+email address. You can use this information in several different ways, such as:
+<ul>
+ <li> As suggestions in forms, so the user doesn't need to input account information by
+hand.</li>
+ <li> As a key into your own online database of usage and personalization information.</li>
+</ul>
+</p>
+
+
+<h2 id="IdIsEnough">Decide Whether Identification is Enough</h2>
+
+<p>Account names are a good way to identify the user, but the {@link android.accounts.Account}
+object by
+itself doesn't protect your data or give you access to anything. If you intend
+to access private data, you'll need something stronger: authentication.
+The next lesson explains how to authenticate to existing online services. The lesson after that
+deals with writing a custom authenticator so that you can install your own
+account types.</p>
diff --git a/docs/html/training/id-auth/index.jd b/docs/html/training/id-auth/index.jd
new file mode 100644
index 0000000..6fbfa65
--- /dev/null
+++ b/docs/html/training/id-auth/index.jd
@@ -0,0 +1,65 @@
+page.title=Identifying and Authenticating Users
+
+trainingnavtop=true
+startpage=true
+next.title=Identifying Your User
+next.link=identify.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Requirements and prerequisites</h2>
+<ul>
+ <li>Android 2.0 (API level 5) or higher</li>
+ <li>Experience with <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a></li>
+ <li>Experience with <a href="http://oauth.net/2/">OAuth 2.0</a></li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a
+href="http://developer.android.com/resources/samples/SampleSyncAdapter/index.html">
+SampleSyncAdapter app</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p>Android users get attached to their devices and to applications that they
+love. One way to make your application lovable is to make it personal. Android
+devices know who your user is, what services they have access to, and where they
+store your data. With your user's permission, you can use that information to
+make your application a richer, more personal experience.</p>
+
+<p>In this class, you will learn multiple techniques for interacting with your
+user's identity, enabling you to:</p>
+
+<ul>
+<li>Identify the user by detecting and selecting an account
+<li>Authenticate the user to make sure they are who they say they are
+<li>Gain permission to access the user's online data via services like
+the Google APIs
+<li>Add a custom account to the user's device to authenticate your own
+back-end services
+</ul>
+
+
+<h2>Lessons</h2>
+
+<dl>
+ <dt><b><a href="identify.html">Identifying Your User</a></b></dt>
+ <dd>Use {@link android.accounts.AccountManager} to learn the user's account name(s).</dd>
+
+ <dt><b><a href="authenticate.html">Authenticating to OAuth2 Services</a></b></dt>
+ <dd> Use OAuth2 to help users get permission to access web services without needing to type in a
+login name or password. </dd>
+
+ <dt><b><a href="custom_auth.html">Creating a Custom Account Type</a></b></dt>
+ <dd>Add your own account type to the Android Account Manager.</dd>
+
+</dl>
+
diff --git a/docs/html/training/monetization/ads-and-ux.jd b/docs/html/training/monetization/ads-and-ux.jd
new file mode 100644
index 0000000..2fec6f2
--- /dev/null
+++ b/docs/html/training/monetization/ads-and-ux.jd
@@ -0,0 +1,250 @@
+page.title=Advertising without Compromising User Experience
+parent.title=Monetizing your App
+parent.link=index.html
+@jd:body
+
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#ObtainPubAccountAndSDK">Obtain a Publisher Account and Ad SDK</a></li>
+ <li><a href="#DeclarePermissions">Declare Proper Permissions</a></li>
+ <li><a href="#SetupAdPlacement">Set Up Ad Placement</a></li>
+ <li><a href="#InitializeAd">Initialize the Ad</a></li>
+ <li><a href="#EnableTestMode">Enable Test Mode</a></li>
+ <li><a href="#ImplementListeners">Implement Ad Event Listeners</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="http://code.google.com/mobile/ads/">AdMob SDK</a></li>
+</ul>
+
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/MobileAds.zip" class="button">Download
+the sample app</a>
+ <p class="filename">MobileAds.zip</p>
+</div>
+
+
+</div>
+</div>
+
+<p>Advertising is one of the means to monetize (make money with) mobile applications. In this
+lesson, you are going to learn how to incorporate banner ads in your Android application.</p>
+
+<p>While this lesson and the sample application use <a
+href="http://code.google.com/mobile/ads/">AdMob</a> to serve ads, the Android platform doesn’t
+impose any restrictions on the choice of mobile advertising network. To the extent possible, this
+lesson generically highlights concepts that are similar across advertising networks.</p>
+
+<p>For example, each advertising network may have some network-specific configuration settings such
+as geo-targeting and ad-text font size, which may be configurable on some networks but not on
+others. This lesson does not touch not these topics in depth and you should consult documentation
+provided by the network you choose.</p>
+
+
+<h2 id="ObtainPubAccountAndSDK">Obtain a Publisher Account and Ad SDK</h2>
+
+<p>In order to integrate advertisements in your application, you first must become a publisher by
+registering a publishing account with the mobile advertising network. Typically, an identifier is
+provisioned for each application serving advertisements. This is how the advertising network
+correlates advertisements served in applications. In the case of AdMob, the identifier is known as
+the Publisher ID. You should consult your advertising networks for details.</p>
+
+<p>Mobile advertising networks typically distribute a specific Android SDK, which consists of code
+that takes care of communication, ad refresh, look-and-feel customization, and so on.</p>
+
+<p>Most advertising networks distribute their SDK as a JAR file. Setting up ad network JAR file in
+your Android project is no different from integrating any third-party JAR files. First, copy the
+JAR files to the <code>libs/</code> directory of your project. If you’re using Eclipse as IDE, be
+sure to add the JAR file to the Build Path. It can be done through <b>Properties >
+Java Build Path > Libraries > Add JARs</b>.</p>
+
+<img src="/images/training/ads-eclipse-build-path.png" id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> Eclipse build path settings.
+</p>
+
+
+<h2 id="DeclarePermissions">Declare Proper Permissions</h2>
+
+<p>Because the mobile ads are fetched over the network, mobile advertising SDKs usually
+require the declaration of related permissions in the Android manifest. Other kinds of permissions
+may also be required.</p>
+
+<p>For example, here's how you can request the {@link android.Manifest.permission#INTERNET}
+permission:</p>
+
+<pre>
+</manifest>
+ <uses-permission android:name="android.permission.INTERNET" />
+ ...
+ <application>...</application>
+</manifest>
+</pre>
+
+
+<h2 id="SetupAdPlacement">Set Up Ad Placement</h2>
+
+<div class="figure" style="width:262px">
+<img src="/images/training/ads-top-banner.png" id="figure2" />
+<p class="img-caption">
+ <strong>Figure 2.</strong> Screenshot of the ad layout in the Mobile Ads sample.
+</p>
+</div>
+
+<p>Banner ads typically are implemented as a custom {@link android.webkit.WebView} (a view for
+viewing web pages). Ads also come in different dimensions and shapes. Once you’ve decided to put an
+ad on a particular screen, you can add it in your activity's XML layout. The XML snippet below
+illustrates a banner ad displayed on top of a screen.</p>
+
+<pre>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/ad_catalog_layout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+ <com.google.ads.AdView
+ xmlns:googleads="http://schemas.android.com/apk/lib/com.google.ads"
+ android:id="@+id/ad"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ googleads:adSize="BANNER"
+ googleads:adUnitId="@string/admob_id" />
+ <TextView android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/banner_top" />
+ <TextView android:id="@+id/status"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+</LinearLayout>
+</pre>
+
+<p>You should consider using alternative ad sizes based on various configurations such as screen
+size or screen orientation. This can easily be addressed by <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">providing
+alternative resources</a>. For instance, the above sample layout might placed under the
+<code>res/layout/</code> directory as the default layout. If larger ad
+sizes are available, you can consider using them for "large" (and above) screens. For example, the
+following snippet comes from a layout file in the <code>res/layout-large/</code> directory, which
+renders a larger ad for "large" screen sizes.</p>
+
+<pre>
+...
+<com.google.ads.AdView
+ xmlns:googleads="http://schemas.android.com/apk/lib/com.google.ads"
+ android:id="@+id/ad"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ <strong>googleads:adSize="IAB_LEADERBOARD"</strong>
+ googleads:adUnitId="@string/admob_id" />
+...
+</pre>
+
+<p>Notice that the custom view name and it’s configuration attributes are network-specific. Ad
+networks might support configurations with XML layout attributes (as shown above), runtime APIs, or
+both. In the sample application, Mobile Ads, the {@code AdView} ad size
+(<code>googleads:adSize</code>) and publisher ID (<code>googleads:adUnitId</code>) are set up in the
+XML layout.</p>
+
+<p>When deciding where to place ads within your application, you should carefully
+consider user-experience. For example, you don’t want to fill the screen with
+multiple ads that will quite likely annoy your users. In fact, this practice is banned by some ad
+networks. Also, avoid placing ads too closely to UI controls to avoid inadvertent clicks.</p>
+
+<p>Figures 3 and 4 illustrate what <strong>not</strong> to do.</p>
+
+<div style="float:left;width:275px">
+<img src="/images/training/ads-close-to-button.png" />
+<p class="img-caption">
+ <strong>Figure 3.</strong> Avoid putting UI
+inputs too closely to an ad banner to prevent inadvertent ad clicks.
+</p>
+</div>
+
+<div style="float:left;width:275px;height:530px;margin-left:2em">
+<img src="/images/training/ads-cover-content.png" />
+<p class="img-caption">
+ <strong>Figure 4.</strong> Don't overlay ad banner on useful content.
+</p>
+</div>
+
+
+<h2 id="InitializeAd" style="clear:left">Initialize the Ad</h2>
+
+<p>After setting up the ad in the XML layout, you can further customize the ad in {@link
+android.app.Activity#onCreate Activity.onCreate()} or {@link
+android.app.Fragment#onCreateView Fragment.onCreateView()} based on how your application is
+architected. Depending on the ad network, possible configuration parameters are: ad size, font
+color, keyword, demographics, location targeting, and so on.</p>
+
+<p>It is important to respect user privacy if certain parameters, such as demographics or location,
+are passed to ad networks for targeting purposes. Let your users know and give them a chance to opt
+out of these features.</p>
+
+<p>In the below code snippet, keyword targeting is used. After the keywords are set, the
+application calls <code>loadAd()</code> to begin serving ads.</p>
+
+<pre>
+public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ...
+ View v = inflater.inflate(R.layout.main, container, false);
+ mAdStatus = (TextView) v.findViewById(R.id.status);
+ mAdView = (AdView) v.findViewById(R.id.ad);
+ mAdView.setAdListener(new MyAdListener());
+
+ AdRequest adRequest = new AdRequest();
+ adRequest.addKeyword("sporting goods");
+ mAdView.loadAd(adRequest);
+ return v;
+}
+</pre>
+
+
+
+<h2 id="EnableTestMode">Enable Test Mode</h2>
+
+<p>Some ad networks provide a test mode. This is useful during development and testing in which ad
+impressions and clicks are not counted.</p>
+
+<p class="caution"><strong>Important:</strong> Be sure to turn off test mode before publishing your
+application.</p>
+
+
+<h2 id="ImplementListeners">Implement Ad Event Listeners</h2>
+
+<p>Where available, you should consider implementing ad event listeners, which provide callbacks on
+various ad-serving events associated with the ad view. Depending on the ad network, the listener
+might provide notifications on events such as before the ad is loaded, after the ad is loaded,
+whether the ad fails to load, or other events. You can choose to react to these events based on
+your specific situation. For example, if the ad fails to load, you can display a custom banner
+within the application or create a layout such that the rest of content fills up the screen.</p>
+
+<p>For example, here are some event callbacks available from AdMob's {@code AdListener}
+interface:</p>
+
+<pre>
+private class MyAdListener implements AdListener {
+ ...
+
+ @Override
+ public void onFailedToReceiveAd(Ad ad, ErrorCode errorCode) {
+ mAdStatus.setText(R.string.error_receive_ad);
+ }
+
+ @Override
+ public void onReceiveAd(Ad ad) {
+ mAdStatus.setText("");
+ }
+}
+</pre>
+
diff --git a/docs/html/training/monetization/index.jd b/docs/html/training/monetization/index.jd
new file mode 100644
index 0000000..f90bfc7
--- /dev/null
+++ b/docs/html/training/monetization/index.jd
@@ -0,0 +1,44 @@
+page.title=Monetizing Your App
+
+trainingnavtop=true
+startpage=true
+next.title=Advertising without Compromising User Experience
+next.link=ads-and-ux.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 1.0 or higher</li>
+ <li>Experience with <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML layouts</a></li>
+</ul>
+
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/MobileAds.zip" class="button">Download
+the sample app</a>
+ <p class="filename">MobileAds.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>Apart from offering paid apps, there are a number of other ways to monetize your mobile applications. In this class, we are going to examine a number of typical methods (more lessons are to come) and their associated technical best practices. Obviously, each application is different and you should experiment with different combinations of these and other monetization methods to determine what works best for you.</p>
+
+<h2>Lessons</h2>
+
+<!-- Create a list of the lessons in this class along with a short description of each lesson.
+These should be short and to the point. It should be clear from reading the summary whether someone
+will want to jump to a lesson or not.-->
+
+<dl>
+ <dt><b><a href="ads-and-ux.html">Advertising without Compromising User Experience</a></b></dt>
+ <dd>In this lesson, you will learn how to monetize your application with mobile
+advertisements.</dd>
+</dl>
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index cb3d833..b106042 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -75,15 +75,15 @@
size_t size;
union {
void* raw;
- short* i16;
- int8_t* i8;
+ short* i16; // signed 16-bit
+ int8_t* i8; // unsigned 8-bit, offset by 0x80
};
};
/* As a convenience, if a callback is supplied, a handler thread
* is automatically created with the appropriate priority. This thread
- * invokes the callback when a new buffer becomes availlable or an underrun condition occurs.
+ * invokes the callback when a new buffer becomes available or an underrun condition occurs.
* Parameters:
*
* event: type of event notified (see enum AudioTrack::event_type).
@@ -94,8 +94,8 @@
* written.
* - EVENT_UNDERRUN: unused.
* - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
- * - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames.
- * - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames.
+ * - EVENT_MARKER: pointer to an uint32_t containing the marker position in frames.
+ * - EVENT_NEW_POS: pointer to an uint32_t containing the new position in frames.
* - EVENT_BUFFER_END: unused.
*/
@@ -135,9 +135,10 @@
* flags: Reserved for future use.
* cbf: Callback function. If not null, this function is called periodically
* to request new PCM data.
+ * user: Context for use by the callback receiver.
* notificationFrames: The callback function is called each time notificationFrames PCM
- * frames have been comsumed from track input buffer.
- * user Context for use by the callback receiver.
+ * frames have been consumed from track input buffer.
+ * sessionId: Specific session ID, or zero to use default.
*/
AudioTrack( int streamType,
@@ -152,11 +153,11 @@
int sessionId = 0);
/* Creates an audio track and registers it with AudioFlinger. With this constructor,
- * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
+ * the PCM data to be rendered by AudioTrack is passed in a shared memory buffer
* identified by the argument sharedBuffer. This prototype is for static buffer playback.
- * PCM data must be present into memory before the AudioTrack is started.
- * The Write() and Flush() methods are not supported in this case.
- * It is recommented to pass a callback function to be notified of playback end by an
+ * PCM data must be present in memory before the AudioTrack is started.
+ * The write() and flush() methods are not supported in this case.
+ * It is recommended to pass a callback function to be notified of playback end by an
* EVENT_UNDERRUN event.
*/
@@ -172,15 +173,15 @@
int sessionId = 0);
/* Terminates the AudioTrack and unregisters it from AudioFlinger.
- * Also destroys all resources assotiated with the AudioTrack.
+ * Also destroys all resources associated with the AudioTrack.
*/
~AudioTrack();
/* Initialize an uninitialized AudioTrack.
* Returned status (from utils/Errors.h) can be:
- * - NO_ERROR: successful intialization
- * - INVALID_OPERATION: AudioTrack is already intitialized
+ * - NO_ERROR: successful initialization
+ * - INVALID_OPERATION: AudioTrack is already initialized
* - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
* - NO_INIT: audio server or audio hardware not initialized
* */
@@ -199,13 +200,13 @@
/* Result of constructing the AudioTrack. This must be checked
- * before using any AudioTrack API (except for set()), using
+ * before using any AudioTrack API (except for set()), because using
* an uninitialized AudioTrack produces undefined results.
* See set() method above for possible return codes.
*/
status_t initCheck() const;
- /* Returns this track's latency in milliseconds.
+ /* Returns this track's estimated latency in milliseconds.
* This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
* and audio hardware driver.
*/
@@ -233,8 +234,8 @@
void stop();
bool stopped() const;
- /* flush a stopped track. All pending buffers are discarded.
- * This function has no effect if the track is not stoped.
+ /* Flush a stopped track. All pending buffers are discarded.
+ * This function has no effect if the track is not stopped.
*/
void flush();
@@ -244,26 +245,25 @@
*/
void pause();
- /* mute or unmutes this track.
- * While mutted, the callback, if set, is still called.
+ /* Mute or unmute this track.
+ * While muted, the callback, if set, is still called.
*/
void mute(bool);
bool muted() const;
-
- /* set volume for this track, mostly used for games' sound effects
- * left and right volumes. Levels must be <= 1.0.
+ /* Set volume for this track, mostly used for games' sound effects
+ * left and right volumes. Levels must be >= 0.0 and <= 1.0.
*/
status_t setVolume(float left, float right);
void getVolume(float* left, float* right);
- /* set the send level for this track. An auxiliary effect should be attached
- * to the track with attachEffect(). Level must be <= 1.0.
+ /* Set the send level for this track. An auxiliary effect should be attached
+ * to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
*/
status_t setAuxEffectSendLevel(float level);
void getAuxEffectSendLevel(float* level);
- /* set sample rate for this track, mostly used for games' sound effects
+ /* Set sample rate for this track, mostly used for games' sound effects
*/
status_t setSampleRate(int sampleRate);
uint32_t getSampleRate();
@@ -274,8 +274,8 @@
*
* loopStart: loop start expressed as the number of PCM frames played since AudioTrack start.
* loopEnd: loop end expressed as the number of PCM frames played since AudioTrack start.
- * loopCount: number of loops to execute. Calling setLoop() with loopCount == 0 cancels any pending or
- * active loop. loopCount = -1 means infinite looping.
+ * loopCount: number of loops to execute. Calling setLoop() with loopCount == 0 cancels any
+ * pending or active loop. loopCount = -1 means infinite looping.
*
* For proper operation the following condition must be respected:
* (loopEnd-loopStart) <= framecount()
@@ -283,10 +283,9 @@
status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount);
-
- /* Sets marker position. When playback reaches the number of frames specified, a callback with event
- * type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker notification
- * callback.
+ /* Sets marker position. When playback reaches the number of frames specified, a callback with
+ * event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
+ * notification callback.
* If the AudioTrack has been opened with no callback function associated, the operation will fail.
*
* Parameters:
@@ -301,10 +300,10 @@
status_t getMarkerPosition(uint32_t *marker);
- /* Sets position update period. Every time the number of frames specified has been played,
- * a callback with event type EVENT_NEW_POS is called.
- * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
- * callback.
+ /* Sets position update period. Every time the number of frames specified has been played,
+ * a callback with event type EVENT_NEW_POS is called.
+ * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
+ * callback.
* If the AudioTrack has been opened with no callback function associated, the operation will fail.
*
* Parameters:
@@ -318,12 +317,11 @@
status_t setPositionUpdatePeriod(uint32_t updatePeriod);
status_t getPositionUpdatePeriod(uint32_t *updatePeriod);
-
/* Sets playback head position within AudioTrack buffer. The new position is specified
- * in number of frames.
+ * in number of frames.
* This method must be called with the AudioTrack in paused or stopped state.
- * Note that the actual position set is <position> modulo the AudioTrack buffer size in frames.
- * Therefore using this method makes sense only when playing a "static" audio buffer
+ * Note that the actual position set is <position> modulo the AudioTrack buffer size in frames.
+ * Therefore using this method makes sense only when playing a "static" audio buffer
* as opposed to streaming.
* The getPosition() method on the other hand returns the total number of frames played since
* playback start.
@@ -335,12 +333,12 @@
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
* - INVALID_OPERATION: the AudioTrack is not stopped.
- * - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack buffer
+ * - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack buffer
*/
status_t setPosition(uint32_t position);
status_t getPosition(uint32_t *position);
- /* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids
+ /* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids
* rewriting the buffer before restarting playback after a stop.
* This method must be called with the AudioTrack in paused or stopped state.
*
@@ -350,7 +348,7 @@
*/
status_t reload();
- /* returns a handle on the audio output used by this AudioTrack.
+ /* Returns a handle on the audio output used by this AudioTrack.
*
* Parameters:
* none.
@@ -360,18 +358,17 @@
*/
audio_io_handle_t getOutput();
- /* returns the unique ID associated to this track.
+ /* Returns the unique session ID associated with this track.
*
* Parameters:
* none.
*
* Returned value:
- * AudioTrack ID.
+ * AudioTrack session ID.
*/
int getSessionId();
-
- /* Attach track auxiliary output to specified effect. Used effectId = 0
+ /* Attach track auxiliary output to specified effect. Use effectId = 0
* to detach track from effect.
*
* Parameters:
@@ -385,9 +382,9 @@
*/
status_t attachAuxEffect(int effectId);
- /* obtains a buffer of "frameCount" frames. The buffer must be
+ /* Obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
- * STOPPED instead of NO_ERROR as long as there are buffers availlable,
+ * STOPPED instead of NO_ERROR as long as there are buffers available,
* at which point NO_MORE_BUFFERS is returned.
* Buffers will be returned until the pool (buffercount())
* is exhausted, at which point obtainBuffer() will either block
@@ -403,10 +400,9 @@
status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
void releaseBuffer(Buffer* audioBuffer);
-
/* As a convenience we provide a write() interface to the audio buffer.
* This is implemented on top of lockBuffer/unlockBuffer. For best
- * performance
+ * performance use callbacks. Return actual number of bytes written.
*
*/
ssize_t write(const void* buffer, size_t size);
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 47d530b..3fa2bf8 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -46,13 +46,13 @@
*/
virtual void stop() = 0;
- /* flush a stopped track. All pending buffers are discarded.
- * This function has no effect if the track is not stoped.
+ /* Flush a stopped track. All pending buffers are discarded.
+ * This function has no effect if the track is not stopped.
*/
virtual void flush() = 0;
- /* mute or unmutes this track.
- * While mutted, the callback, if set, is still called.
+ /* Mute or unmute this track.
+ * While muted, the callback, if set, is still called.
*/
virtual void mute(bool) = 0;
@@ -67,7 +67,7 @@
*/
virtual status_t attachAuxEffect(int effectId) = 0;
- /* get this tracks control block */
+ /* get this track's control block */
virtual sp<IMemory> getCblk() const = 0;
};
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 20abd51..046d5e9 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -59,8 +59,8 @@
// The data members are grouped so that members accessed frequently and in the same context
// are in the same line of data cache.
- Mutex lock;
- Condition cv;
+ Mutex lock; // sizeof(int)
+ Condition cv; // sizeof(int)
volatile uint32_t user;
volatile uint32_t server;
uint32_t userBase;
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index c3bac5d..f2205f6 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -79,6 +79,8 @@
mTexCoordsArrayEnabled = false;
+ mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
+
glActiveTexture(gTextureUnits[0]);
mTextureUnit = 0;
@@ -312,6 +314,17 @@
}
}
+void Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
+ if (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight) {
+ glScissor(x, y, width, height);
+
+ mScissorX = x;
+ mScissorY = y;
+ mScissorWidth = width;
+ mScissorHeight = height;
+ }
+}
+
TextureVertex* Caches::getRegionMesh() {
// Create the mesh, 2 triangles and 4 vertices per rectangle in the region
if (!mRegionMesh) {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index edf3a47..d264971 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -188,6 +188,11 @@
void activeTexture(GLuint textureUnit);
/**
+ * Sets the scissor for the current surface.
+ */
+ void setScissor(GLint x, GLint y, GLint width, GLint height);
+
+ /**
* Returns the mesh used to draw regions. Calling this method will
* bind a VBO of type GL_ELEMENT_ARRAY_BUFFER that contains the
* indices for the region mesh.
@@ -240,6 +245,11 @@
GLuint mTextureUnit;
+ GLint mScissorX;
+ GLint mScissorY;
+ GLint mScissorWidth;
+ GLint mScissorHeight;
+
// Used to render layers
TextureVertex* mRegionMesh;
GLuint mRegionMeshIndices;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cbfd778..75c6d0a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -155,7 +155,7 @@
mSaveCount = 1;
glViewport(0, 0, mWidth, mHeight);
- glScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
+ mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
mSnapshot->setClip(left, top, right, bottom);
mDirtyClip = false;
@@ -550,7 +550,7 @@
#endif
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
- glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
+ mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
glClear(GL_COLOR_BUFFER_BIT);
@@ -965,7 +965,10 @@
void OpenGLRenderer::setScissorFromClip() {
Rect clip(*mSnapshot->clipRect);
clip.snapToPixelBoundaries();
- glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
+
+ mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
+ clip.getWidth(), clip.getHeight());
+
mDirtyClip = false;
}
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index fb76717..fff9f6c 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -112,7 +112,8 @@
}
bool intersect(float l, float t, float r, float b) {
- Rect tmp(intersectWith(l, t, r, b));
+ Rect tmp(l, t, r, b);
+ intersectWith(tmp);
if (!tmp.isEmpty()) {
set(tmp);
return true;
@@ -173,6 +174,13 @@
static inline float min(float a, float b) { return (a < b) ? a : b; }
static inline float max(float a, float b) { return (a > b) ? a : b; }
+ void intersectWith(Rect& tmp) const {
+ tmp.left = max(left, tmp.left);
+ tmp.top = max(top, tmp.top);
+ tmp.right = min(right, tmp.right);
+ tmp.bottom = min(bottom, tmp.bottom);
+ }
+
Rect intersectWith(float l, float t, float r, float b) const {
Rect tmp;
tmp.left = max(left, l);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 4f9eb2b..c5d17eb 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -449,7 +449,7 @@
// AudioTrack subclasses too.
try {
stop();
- } catch(IllegalStateException ise) {
+ } catch(IllegalStateException ise) {
// don't raise an exception, we're releasing the resources.
}
native_release();
@@ -488,7 +488,7 @@
public int getSampleRate() {
return mSampleRate;
}
-
+
/**
* Returns the current playback rate in Hz.
*/
@@ -590,22 +590,22 @@
static public int getNativeOutputSampleRate(int streamType) {
return native_get_output_sample_rate(streamType);
}
-
+
/**
* Returns the minimum buffer size required for the successful creation of an AudioTrack
* object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't
* guarantee a smooth playback under load, and higher values should be chosen according to
- * the expected frequency at which the buffer will be refilled with additional data to play.
+ * the expected frequency at which the buffer will be refilled with additional data to play.
* @param sampleRateInHz the sample rate expressed in Hertz.
- * @param channelConfig describes the configuration of the audio channels.
+ * @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
- * @param audioFormat the format in which the audio data is represented.
- * See {@link AudioFormat#ENCODING_PCM_16BIT} and
+ * @param audioFormat the format in which the audio data is represented.
+ * See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
* @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
- * or {@link #ERROR} if the implementation was unable to query the hardware for its output
- * properties,
+ * or {@link #ERROR} if the implementation was unable to query the hardware for its output
+ * properties,
* or the minimum buffer size expressed in bytes.
*/
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
@@ -623,18 +623,18 @@
loge("getMinBufferSize(): Invalid channel configuration.");
return AudioTrack.ERROR_BAD_VALUE;
}
-
- if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
+
+ if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
&& (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
loge("getMinBufferSize(): Invalid audio format.");
return AudioTrack.ERROR_BAD_VALUE;
}
-
+
if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
return AudioTrack.ERROR_BAD_VALUE;
}
-
+
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
if ((size == -1) || (size == 0)) {
loge("getMinBufferSize(): error querying hardware");
@@ -667,7 +667,7 @@
public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener) {
setPlaybackPositionUpdateListener(listener, null);
}
-
+
/**
* Sets the listener the AudioTrack notifies when a previously set marker is reached or
* for each periodic playback head position update.
@@ -676,7 +676,7 @@
* @param listener
* @param handler the Handler that will receive the event notification messages.
*/
- public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
+ public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener,
Handler handler) {
synchronized (mPositionListenerLock) {
mPositionListener = listener;
@@ -684,7 +684,7 @@
if (listener != null) {
mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler);
}
-
+
}
@@ -917,7 +917,7 @@
return ERROR_INVALID_OPERATION;
}
- if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
+ if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
|| (offsetInBytes + sizeInBytes > audioData.length)) {
return ERROR_BAD_VALUE;
}
@@ -948,12 +948,12 @@
&& (sizeInShorts > 0)) {
mState = STATE_INITIALIZED;
}
-
+
if (mState != STATE_INITIALIZED) {
return ERROR_INVALID_OPERATION;
}
- if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
+ if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
|| (offsetInShorts + sizeInShorts > audioData.length)) {
return ERROR_BAD_VALUE;
}
@@ -1047,7 +1047,7 @@
* by the playback head.
*/
void onMarkerReached(AudioTrack track);
-
+
/**
* Called on the listener to periodically notify it that the playback head has reached
* a multiple of the notification period.
@@ -1066,7 +1066,7 @@
private class NativeEventHandlerDelegate {
private final AudioTrack mAudioTrack;
private final Handler mHandler;
-
+
NativeEventHandlerDelegate(AudioTrack track, Handler handler) {
mAudioTrack = track;
// find the looper for our new event handler
@@ -1077,7 +1077,7 @@
// no given handler, use the looper the AudioTrack was created in
looper = mInitializationLooper;
}
-
+
// construct the event handler with this looper
if (looper != null) {
// implement the event handler delegate
@@ -1111,9 +1111,9 @@
};
} else {
mHandler = null;
- }
+ }
}
-
+
Handler getHandler() {
return mHandler;
}
@@ -1133,7 +1133,7 @@
}
if (track.mEventHandlerDelegate != null) {
- Message m =
+ Message m =
track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj);
track.mEventHandlerDelegate.getHandler().sendMessage(m);
}
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index af713fb..6868d99 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1,4 +1,4 @@
-/* //device/extlibs/pv/android/AudioTrack.cpp
+/* frameworks/base/media/libmedia/AudioTrack.cpp
**
** Copyright 2007, The Android Open Source Project
**
@@ -1467,4 +1467,3 @@
// -------------------------------------------------------------------------
}; // namespace android
-
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index d0d9ca6..3539e3f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -376,7 +376,7 @@
bool tooLate = (mVideoLateByUs > 40000);
if (tooLate) {
- ALOGV("video late by %lld us (%.2f secs)", lateByUs, lateByUs / 1E6);
+ ALOGV("video late by %lld us (%.2f secs)", mVideoLateByUs, mVideoLateByUs / 1E6);
} else {
ALOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2b4e415..fd82306 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -397,7 +397,7 @@
int lSessionId;
if (streamType >= AUDIO_STREAM_CNT) {
- LOGE("invalid stream type");
+ LOGE("createTrack() invalid stream type %d", streamType);
lStatus = BAD_VALUE;
goto Exit;
}
@@ -429,6 +429,7 @@
// prevent same audio session on different output threads
uint32_t sessions = t->hasAudioSession(*sessionId);
if (sessions & PlaybackThread::TRACK_SESSION) {
+ LOGE("createTrack() session ID %d already in use", *sessionId);
lStatus = BAD_VALUE;
goto Exit;
}
@@ -659,6 +660,7 @@
}
if (stream < 0 || uint32_t(stream) >= AUDIO_STREAM_CNT) {
+ LOGE("setStreamVolume() invalid stream %d", stream);
return BAD_VALUE;
}
@@ -693,6 +695,7 @@
if (stream < 0 || uint32_t(stream) >= AUDIO_STREAM_CNT ||
uint32_t(stream) == AUDIO_STREAM_ENFORCED_AUDIBLE) {
+ LOGE("setStreamMute() invalid stream %d", stream);
return BAD_VALUE;
}
@@ -1000,7 +1003,7 @@
void AudioFlinger::ThreadBase::exit()
{
- // keep a strong ref on ourself so that we wont get
+ // keep a strong ref on ourself so that we won't get
// destroyed in the middle of requestExitAndWait()
sp <ThreadBase> strongMe = this;
@@ -1527,8 +1530,10 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
sp<Track> t = mTracks[i];
if (t != 0) {
- if (sessionId == t->sessionId() &&
- strategy != AudioSystem::getStrategyForStream((audio_stream_type_t)t->type())) {
+ uint32_t actual = AudioSystem::getStrategyForStream((audio_stream_type_t)t->type());
+ if (sessionId == t->sessionId() && strategy != actual) {
+ LOGE("createTrack_l() mismatched strategy; expected %u but found %u",
+ strategy, actual);
lStatus = BAD_VALUE;
goto Exit;
}
@@ -1968,7 +1973,7 @@
// during mixing and effect process as the audio buffers could be deleted
// or modified if an effect is created or deleted
lockEffectChains_l(effectChains);
- }
+ }
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
// mix buffers...
@@ -2013,11 +2018,11 @@
}
// sleepTime == 0 means we must write to audio hardware
if (sleepTime == 0) {
- for (size_t i = 0; i < effectChains.size(); i ++) {
- effectChains[i]->process_l();
- }
- // enable changes in effect chain
- unlockEffectChains(effectChains);
+ for (size_t i = 0; i < effectChains.size(); i ++) {
+ effectChains[i]->process_l();
+ }
+ // enable changes in effect chain
+ unlockEffectChains(effectChains);
mLastWriteTime = systemTime();
mInWrite = true;
mBytesWritten += mixBufferSize;
@@ -2345,7 +2350,7 @@
}
if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
// do not accept frame count changes if tracks are open as the track buffer
- // size depends on frame count and correct behavior would not be garantied
+ // size depends on frame count and correct behavior would not be guaranteed
// if frame count is changed after track creation
if (!mTracks.isEmpty()) {
status = INVALID_OPERATION;
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 7c7fa56..847f8dc 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -58,10 +58,16 @@
t->needs = 0;
t->volume[0] = UNITY_GAIN;
t->volume[1] = UNITY_GAIN;
+ // no initialization needed
+ // t->prevVolume[0]
+ // t->prevVolume[1]
t->volumeInc[0] = 0;
t->volumeInc[1] = 0;
t->auxLevel = 0;
t->auxInc = 0;
+ // no initialization needed
+ // t->prevAuxLevel
+ // t->frameCount
t->channelCount = 2;
t->enabled = 0;
t->format = 16;
@@ -78,19 +84,19 @@
}
}
- AudioMixer::~AudioMixer()
- {
- track_t* t = mState.tracks;
- for (int i=0 ; i<32 ; i++) {
- delete t->resampler;
- t++;
- }
- delete [] mState.outputTemp;
- delete [] mState.resampleTemp;
- }
+AudioMixer::~AudioMixer()
+{
+ track_t* t = mState.tracks;
+ for (int i=0 ; i<32 ; i++) {
+ delete t->resampler;
+ t++;
+ }
+ delete [] mState.outputTemp;
+ delete [] mState.resampleTemp;
+}
- int AudioMixer::getTrackName()
- {
+int AudioMixer::getTrackName()
+{
uint32_t names = mTrackNames;
uint32_t mask = 1;
int n = 0;
@@ -104,18 +110,18 @@
return TRACK0 + n;
}
return -1;
- }
+}
- void AudioMixer::invalidateState(uint32_t mask)
- {
+void AudioMixer::invalidateState(uint32_t mask)
+{
if (mask) {
mState.needsChanged |= mask;
mState.hook = process__validate;
}
}
- void AudioMixer::deleteTrackName(int name)
- {
+void AudioMixer::deleteTrackName(int name)
+{
name -= TRACK0;
if (uint32_t(name) < MAX_NUM_TRACKS) {
ALOGV("deleteTrackName(%d)", name);
@@ -135,7 +141,7 @@
track.volumeInc[1] = 0;
mTrackNames &= ~(1<<name);
}
- }
+}
status_t AudioMixer::enable(int name)
{
@@ -450,33 +456,33 @@
countActiveTracks, state->enabledTracks,
all16BitsStereoNoResample, resampling, volumeRamp);
- state->hook(state);
+ state->hook(state);
- // Now that the volume ramp has been done, set optimal state and
- // track hooks for subsequent mixer process
- if (countActiveTracks) {
- int allMuted = 1;
- uint32_t en = state->enabledTracks;
- while (en) {
- const int i = 31 - __builtin_clz(en);
- en &= ~(1<<i);
- track_t& t = state->tracks[i];
- if (!t.doesResample() && t.volumeRL == 0)
- {
- t.needs |= NEEDS_MUTE_ENABLED;
- t.hook = track__nop;
- } else {
- allMuted = 0;
- }
- }
- if (allMuted) {
- state->hook = process__nop;
- } else if (all16BitsStereoNoResample) {
- if (countActiveTracks == 1) {
- state->hook = process__OneTrack16BitsStereoNoResampling;
- }
- }
- }
+ // Now that the volume ramp has been done, set optimal state and
+ // track hooks for subsequent mixer process
+ if (countActiveTracks) {
+ int allMuted = 1;
+ uint32_t en = state->enabledTracks;
+ while (en) {
+ const int i = 31 - __builtin_clz(en);
+ en &= ~(1<<i);
+ track_t& t = state->tracks[i];
+ if (!t.doesResample() && t.volumeRL == 0)
+ {
+ t.needs |= NEEDS_MUTE_ENABLED;
+ t.hook = track__nop;
+ } else {
+ allMuted = 0;
+ }
+ }
+ if (allMuted) {
+ state->hook = process__nop;
+ } else if (all16BitsStereoNoResample) {
+ if (countActiveTracks == 1) {
+ state->hook = process__OneTrack16BitsStereoNoResampling;
+ }
+ }
+ }
}
static inline
@@ -993,7 +999,7 @@
}
- // generic code with resampling
+// generic code with resampling
void AudioMixer::process__genericResampling(state_t* state)
{
int32_t* const outTemp = state->outputTemp;
@@ -1173,7 +1179,7 @@
}
in1 = buff;
b1.frameCount = numFrames;
- } else {
+ } else {
in1 = b1.i16;
}
frameCount1 = b1.frameCount;
@@ -1215,4 +1221,3 @@
// ----------------------------------------------------------------------------
}; // namespace android
-
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 75c9170..da9e2b5 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -65,10 +65,10 @@
FORMAT = 0x4001,
MAIN_BUFFER = 0x4002,
AUX_BUFFER = 0x4003,
- // for TARGET RESAMPLE
+ // for target RESAMPLE
SAMPLE_RATE = 0x4100,
RESET = 0x4101,
- // for TARGET VOLUME (8 channels max)
+ // for target RAMP_VOLUME and VOLUME (8 channels max)
VOLUME0 = 0x4200,
VOLUME1 = 0x4201,
AUXLEVEL = 0x4210,