Merge "Update setAdapter() documentation for Spinner"
diff --git a/Android.mk b/Android.mk
index 98bd88d..1fa8794 100644
--- a/Android.mk
+++ b/Android.mk
@@ -104,6 +104,7 @@
core/java/android/content/IIntentReceiver.aidl \
core/java/android/content/IIntentSender.aidl \
core/java/android/content/IOnPrimaryClipChangedListener.aidl \
+ core/java/android/content/IAnonymousSyncAdapter.aidl \
core/java/android/content/ISyncAdapter.aidl \
core/java/android/content/ISyncContext.aidl \
core/java/android/content/ISyncStatusObserver.aidl \
@@ -339,6 +340,7 @@
frameworks/base/core/java/android/content/Intent.aidl \
frameworks/base/core/java/android/content/IntentSender.aidl \
frameworks/base/core/java/android/content/PeriodicSync.aidl \
+ frameworks/base/core/java/android/content/SyncRequest.aidl \
frameworks/base/core/java/android/content/SyncStats.aidl \
frameworks/base/core/java/android/content/res/Configuration.aidl \
frameworks/base/core/java/android/database/CursorWindow.aidl \
diff --git a/api/current.txt b/api/current.txt
index b0d66fa..2eb6ece 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5574,6 +5574,7 @@
method public final android.os.Bundle call(android.net.Uri, java.lang.String, java.lang.String, android.os.Bundle);
method public deprecated void cancelSync(android.net.Uri);
method public static void cancelSync(android.accounts.Account, java.lang.String);
+ method public static void cancelSync(android.content.SyncRequest);
method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
method public static deprecated android.content.SyncInfo getCurrentSync();
method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
@@ -5601,6 +5602,7 @@
method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
method public static void removeStatusChangeListener(java.lang.Object);
method public static void requestSync(android.accounts.Account, java.lang.String, android.os.Bundle);
+ method public static void requestSync(android.content.SyncRequest);
method public static void setIsSyncable(android.accounts.Account, java.lang.String, int);
method public static void setMasterSyncAutomatically(boolean);
method public static void setSyncAutomatically(android.accounts.Account, java.lang.String, boolean);
@@ -6537,7 +6539,9 @@
field public final android.accounts.Account account;
field public final java.lang.String authority;
field public final android.os.Bundle extras;
+ field public final boolean isService;
field public final long period;
+ field public final android.content.ComponentName service;
}
public class ReceiverCallNotAllowedException extends android.util.AndroidRuntimeException {
@@ -6656,6 +6660,31 @@
field public final long startTime;
}
+ public class SyncRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean isExpedited();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static class SyncRequest.Builder {
+ ctor public SyncRequest.Builder();
+ method public android.content.SyncRequest build();
+ method public android.content.SyncRequest.Builder setAllowMetered(boolean);
+ method public android.content.SyncRequest.Builder setExpedited(boolean);
+ method public android.content.SyncRequest.Builder setExtras(android.os.Bundle);
+ method public android.content.SyncRequest.Builder setIgnoreBackoff(boolean);
+ method public android.content.SyncRequest.Builder setIgnoreSettings(boolean);
+ method public android.content.SyncRequest.Builder setManual(boolean);
+ method public android.content.SyncRequest.Builder setNoRetry(boolean);
+ method public android.content.SyncRequest.Builder setPriority(int);
+ method public android.content.SyncRequest.Builder setSyncAdapter(android.accounts.Account, java.lang.String);
+ method public android.content.SyncRequest.Builder setSyncAdapter(android.content.ComponentName);
+ method public android.content.SyncRequest.Builder setTransferSize(long, long);
+ method public android.content.SyncRequest.Builder syncOnce(long, long);
+ method public android.content.SyncRequest.Builder syncPeriodic(long, long);
+ }
+
public final class SyncResult implements android.os.Parcelable {
ctor public SyncResult();
method public void clear();
@@ -6679,6 +6708,12 @@
field public boolean tooManyRetries;
}
+ public abstract class SyncService extends android.app.Service {
+ ctor public SyncService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onPerformSync(android.os.Bundle, android.content.SyncResult);
+ }
+
public class SyncStats implements android.os.Parcelable {
ctor public SyncStats();
ctor public SyncStats(android.os.Parcel);
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index d10eaea..5c534a1 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -461,8 +461,13 @@
mSocket.close();
mSocket = null;
}
- if(mPfd != null)
- mPfd.detachFd();
+ if(mPfd != null) {
+ try {
+ mPfd.detachFd();
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "ignore IllegalArgumentException");
+ }
+ }
}
}
}
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index bafe67d..613450b 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -147,6 +147,7 @@
}
private class ISyncAdapterImpl extends ISyncAdapter.Stub {
+ @Override
public void startSync(ISyncContext syncContext, String authority, Account account,
Bundle extras) {
final SyncContext syncContextClient = new SyncContext(syncContext);
@@ -184,6 +185,7 @@
}
}
+ @Override
public void cancelSync(ISyncContext syncContext) {
// synchronize to make sure that mSyncThreads doesn't change between when we
// check it and when we use it
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f090e07..243c91a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -44,6 +44,7 @@
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import java.io.File;
import java.io.FileInputStream;
@@ -131,6 +132,19 @@
*/
public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
+ /* Extensions to API. TODO: Not clear if we will keep these as public flags. */
+ /** {@hide} User-specified flag for expected upload size. */
+ public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
+
+ /** {@hide} User-specified flag for expected download size. */
+ public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
+
+ /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */
+ public static final String SYNC_EXTRAS_PRIORITY = "sync_priority";
+
+ /** {@hide} Flag to allow sync to occur on metered network. */
+ public static final String SYNC_EXTRAS_ALLOW_METERED = "allow_metered";
+
/**
* Set by the SyncManager to request that the SyncAdapter initialize itself for
* the given account/authority pair. One required initialization step is to
@@ -1385,6 +1399,8 @@
* <li>Float</li>
* <li>Double</li>
* <li>String</li>
+ * <li>Account</li>
+ * <li>null</li>
* </ul>
*
* @param uri the uri of the provider to sync or null to sync all providers.
@@ -1416,6 +1432,8 @@
* <li>Float</li>
* <li>Double</li>
* <li>String</li>
+ * <li>Account</li>
+ * <li>null</li>
* </ul>
*
* @param account which account should be synced
@@ -1423,10 +1441,24 @@
* @param extras any extras to pass to the SyncAdapter.
*/
public static void requestSync(Account account, String authority, Bundle extras) {
- validateSyncExtrasBundle(extras);
+ SyncRequest request =
+ new SyncRequest.Builder()
+ .setSyncAdapter(account, authority)
+ .setExtras(extras)
+ .syncOnce(0, 0) // Immediate sync.
+ .build();
+ requestSync(request);
+ }
+
+ /**
+ * Register a sync with the SyncManager. These requests are built using the
+ * {@link SyncRequest.Builder}.
+ */
+ public static void requestSync(SyncRequest request) {
try {
- getContentService().requestSync(account, authority, extras);
- } catch (RemoteException e) {
+ getContentService().sync(request);
+ } catch(RemoteException e) {
+ // Shouldn't happen.
}
}
@@ -1586,7 +1618,7 @@
throw new IllegalArgumentException("illegal extras were set");
}
try {
- getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
+ getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
} catch (RemoteException e) {
// exception ignored; if this is thrown then it means the runtime is in the midst of
// being restarted
@@ -1619,6 +1651,22 @@
}
/**
+ * Remove the specified sync. This will remove any syncs that have been scheduled to run, but
+ * will not cancel any running syncs.
+ * <p>This method requires the caller to hold the permission</p>
+ * If the request is for a periodic sync this will cancel future occurrences of the sync.
+ *
+ * It is possible to cancel a sync using a SyncRequest object that is different from the object
+ * with which you requested the sync. Do so by building a SyncRequest with exactly the same
+ * service/adapter, frequency, <b>and</b> extras bundle.
+ *
+ * @param request SyncRequest object containing information about sync to cancel.
+ */
+ public static void cancelSync(SyncRequest request) {
+ // TODO: Finish this implementation.
+ }
+
+ /**
* Get the list of information about the periodic syncs for the given account and authority.
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
diff --git a/core/java/android/content/IAnonymousSyncAdapter.aidl b/core/java/android/content/IAnonymousSyncAdapter.aidl
new file mode 100644
index 0000000..a80cea3
--- /dev/null
+++ b/core/java/android/content/IAnonymousSyncAdapter.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+import android.os.Bundle;
+import android.content.ISyncContext;
+
+/**
+ * Interface to define an anonymous service that is extended by developers
+ * in order to perform anonymous syncs (syncs without an Account or Content
+ * Provider specified). See {@link android.content.AbstractThreadedSyncAdapter}.
+ * {@hide}
+ */
+oneway interface IAnonymousSyncAdapter {
+
+ /**
+ * Initiate a sync. SyncAdapter-specific parameters may be specified in
+ * extras, which is guaranteed to not be null.
+ *
+ * @param syncContext the ISyncContext used to indicate the progress of the sync. When
+ * the sync is finished (successfully or not) ISyncContext.onFinished() must be called.
+ * @param extras SyncAdapter-specific parameters.
+ *
+ */
+ void startSync(ISyncContext syncContext, in Bundle extras);
+
+ /**
+ * Cancel the currently ongoing sync.
+ */
+ void cancelSync(ISyncContext syncContext);
+
+}
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index f956bcf..9ad5a19 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -20,6 +20,7 @@
import android.content.SyncInfo;
import android.content.ISyncStatusObserver;
import android.content.SyncAdapterType;
+import android.content.SyncRequest;
import android.content.SyncStatusInfo;
import android.content.PeriodicSync;
import android.net.Uri;
@@ -54,6 +55,7 @@
int userHandle);
void requestSync(in Account account, String authority, in Bundle extras);
+ void sync(in SyncRequest request);
void cancelSync(in Account account, String authority);
/**
diff --git a/core/java/android/content/PeriodicSync.java b/core/java/android/content/PeriodicSync.java
index 513a556..6aca151 100644
--- a/core/java/android/content/PeriodicSync.java
+++ b/core/java/android/content/PeriodicSync.java
@@ -22,67 +22,170 @@
import android.accounts.Account;
/**
- * Value type that contains information about a periodic sync. Is parcelable, making it suitable
- * for passing in an IPC.
+ * Value type that contains information about a periodic sync.
*/
public class PeriodicSync implements Parcelable {
- /** The account to be synced */
+ /** The account to be synced. Can be null. */
public final Account account;
- /** The authority of the sync */
+ /** The authority of the sync. Can be null. */
public final String authority;
+ /** The service for syncing, if this is an anonymous sync. Can be null.*/
+ public final ComponentName service;
/** Any extras that parameters that are to be passed to the sync adapter. */
public final Bundle extras;
- /** How frequently the sync should be scheduled, in seconds. */
+ /** How frequently the sync should be scheduled, in seconds. Kept around for API purposes. */
public final long period;
+ /** Whether this periodic sync uses a service. */
+ public final boolean isService;
+ /**
+ * How much flexibility can be taken in scheduling the sync, in seconds.
+ * {@hide}
+ */
+ public final long flexTime;
- /** Creates a new PeriodicSync, copying the Bundle */
- public PeriodicSync(Account account, String authority, Bundle extras, long period) {
+ /**
+ * Creates a new PeriodicSync, copying the Bundle. SM no longer uses this ctor - kept around
+ * becuse it is part of the API.
+ * Note - even calls to the old API will not use this ctor, as
+ * they are given a default flex time.
+ */
+ public PeriodicSync(Account account, String authority, Bundle extras, long periodInSeconds) {
this.account = account;
this.authority = authority;
- this.extras = new Bundle(extras);
- this.period = period;
+ this.service = null;
+ this.isService = false;
+ if (extras == null) {
+ this.extras = new Bundle();
+ } else {
+ this.extras = new Bundle(extras);
+ }
+ this.period = periodInSeconds;
+ // Old API uses default flex time. No-one should be using this ctor anyway.
+ this.flexTime = 0L;
}
+ // TODO: Add copy ctor from SyncRequest?
+
+ /**
+ * Create a copy of a periodic sync.
+ * {@hide}
+ */
+ public PeriodicSync(PeriodicSync other) {
+ this.account = other.account;
+ this.authority = other.authority;
+ this.service = other.service;
+ this.isService = other.isService;
+ this.extras = new Bundle(other.extras);
+ this.period = other.period;
+ this.flexTime = other.flexTime;
+ }
+
+ /**
+ * A PeriodicSync for a sync with a specified provider.
+ * {@hide}
+ */
+ public PeriodicSync(Account account, String authority, Bundle extras,
+ long period, long flexTime) {
+ this.account = account;
+ this.authority = authority;
+ this.service = null;
+ this.isService = false;
+ this.extras = new Bundle(extras);
+ this.period = period;
+ this.flexTime = flexTime;
+ }
+
+ /**
+ * A PeriodicSync for a sync with a specified SyncService.
+ * {@hide}
+ */
+ public PeriodicSync(ComponentName service, Bundle extras,
+ long period,
+ long flexTime) {
+ this.account = null;
+ this.authority = null;
+ this.service = service;
+ this.isService = true;
+ this.extras = new Bundle(extras);
+ this.period = period;
+ this.flexTime = flexTime;
+ }
+
+ private PeriodicSync(Parcel in) {
+ this.isService = (in.readInt() != 0);
+ if (this.isService) {
+ this.service = in.readParcelable(null);
+ this.account = null;
+ this.authority = null;
+ } else {
+ this.account = in.readParcelable(null);
+ this.authority = in.readString();
+ this.service = null;
+ }
+ this.extras = in.readBundle();
+ this.period = in.readLong();
+ this.flexTime = in.readLong();
+ }
+
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int flags) {
- account.writeToParcel(dest, flags);
- dest.writeString(authority);
+ dest.writeInt(isService ? 1 : 0);
+ if (account == null && authority == null) {
+ dest.writeParcelable(service, flags);
+ } else {
+ dest.writeParcelable(account, flags);
+ dest.writeString(authority);
+ }
dest.writeBundle(extras);
dest.writeLong(period);
+ dest.writeLong(flexTime);
}
public static final Creator<PeriodicSync> CREATOR = new Creator<PeriodicSync>() {
+ @Override
public PeriodicSync createFromParcel(Parcel source) {
- return new PeriodicSync(Account.CREATOR.createFromParcel(source),
- source.readString(), source.readBundle(), source.readLong());
+ return new PeriodicSync(source);
}
+ @Override
public PeriodicSync[] newArray(int size) {
return new PeriodicSync[size];
}
};
+ @Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
-
if (!(o instanceof PeriodicSync)) {
return false;
}
-
final PeriodicSync other = (PeriodicSync) o;
-
- return account.equals(other.account)
- && authority.equals(other.authority)
- && period == other.period
- && syncExtrasEquals(extras, other.extras);
+ if (this.isService != other.isService) {
+ return false;
+ }
+ boolean equal = false;
+ if (this.isService) {
+ equal = service.equals(other.service);
+ } else {
+ equal = account.equals(other.account)
+ && authority.equals(other.authority);
+ }
+ return equal
+ && period == other.period
+ && syncExtrasEquals(extras, other.extras);
}
- /** {@hide} */
+ /**
+ * Periodic sync extra comparison function.
+ * {@hide}
+ */
public static boolean syncExtrasEquals(Bundle b1, Bundle b2) {
if (b1.size() != b2.size()) {
return false;
@@ -100,4 +203,13 @@
}
return true;
}
+
+ @Override
+ public String toString() {
+ return "account: " + account +
+ ", authority: " + authority +
+ ", service: " + service +
+ ". period: " + period + "s " +
+ ", flex: " + flexTime;
+ }
}
diff --git a/core/java/android/content/SyncRequest.aidl b/core/java/android/content/SyncRequest.aidl
new file mode 100644
index 0000000..8321fac
--- /dev/null
+++ b/core/java/android/content/SyncRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+parcelable SyncRequest;
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
new file mode 100644
index 0000000..336371e
--- /dev/null
+++ b/core/java/android/content/SyncRequest.java
@@ -0,0 +1,625 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.accounts.Account;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Pair;
+
+public class SyncRequest implements Parcelable {
+ private static final String TAG = "SyncRequest";
+ /** Account to pass to the sync adapter. Can be null. */
+ private final Account mAccountToSync;
+ /** Authority string that corresponds to a ContentProvider. */
+ private final String mAuthority;
+ /** {@link SyncService} identifier. */
+ private final ComponentName mComponentInfo;
+ /** Bundle containing user info as well as sync settings. */
+ private final Bundle mExtras;
+ /** Allow this sync request on metered networks. */
+ private final boolean mAllowMetered;
+ /**
+ * Anticipated upload size in bytes.
+ * TODO: Not yet used - we put this information into the bundle for simplicity.
+ */
+ private final long mTxBytes;
+ /**
+ * Anticipated download size in bytes.
+ * TODO: Not yet used - we put this information into the bundle.
+ */
+ private final long mRxBytes;
+ /**
+ * Amount of time before {@link mSyncRunTimeSecs} from which the sync may optionally be
+ * started.
+ */
+ private final long mSyncFlexTimeSecs;
+ /**
+ * Specifies a point in the future at which the sync must have been scheduled to run.
+ */
+ private final long mSyncRunTimeSecs;
+ /** Periodic versus one-off. */
+ private final boolean mIsPeriodic;
+ /** Service versus provider. */
+ private final boolean mIsAuthority;
+ /** Sync should be run in lieu of other syncs. */
+ private final boolean mIsExpedited;
+
+ /**
+ * {@hide}
+ * @return whether this sync is periodic or one-time. A Sync Request must be
+ * either one of these or an InvalidStateException will be thrown in
+ * Builder.build().
+ */
+ public boolean isPeriodic() {
+ return mIsPeriodic;
+ }
+
+ public boolean isExpedited() {
+ return mIsExpedited;
+ }
+
+ /**
+ * {@hide}
+ * @return true if this sync uses an account/authority pair, or false if
+ * this is an anonymous sync bound to an @link AnonymousSyncService.
+ */
+ public boolean hasAuthority() {
+ return mIsAuthority;
+ }
+
+ /**
+ * {@hide}
+ * Throws a runtime IllegalArgumentException if this function is called for an
+ * anonymous sync.
+ *
+ * @return (Account, Provider) for this SyncRequest.
+ */
+ public Pair<Account, String> getProviderInfo() {
+ if (!hasAuthority()) {
+ throw new IllegalArgumentException("Cannot getProviderInfo() for an anonymous sync.");
+ }
+ return Pair.create(mAccountToSync, mAuthority);
+ }
+
+ /**
+ * {@hide}
+ * Throws a runtime IllegalArgumentException if this function is called for a
+ * SyncRequest that is bound to an account/provider.
+ *
+ * @return ComponentName for the service that this sync will bind to.
+ */
+ public ComponentName getService() {
+ if (hasAuthority()) {
+ throw new IllegalArgumentException(
+ "Cannot getAnonymousService() for a sync that has specified a provider.");
+ }
+ return mComponentInfo;
+ }
+
+ /**
+ * {@hide}
+ * Retrieve bundle for this SyncRequest. Will not be null.
+ */
+ public Bundle getBundle() {
+ return mExtras;
+ }
+
+ /**
+ * {@hide}
+ * @return the earliest point in time that this sync can be scheduled.
+ */
+ public long getSyncFlexTime() {
+ return mSyncFlexTimeSecs;
+ }
+ /**
+ * {@hide}
+ * @return the last point in time at which this sync must scheduled.
+ */
+ public long getSyncRunTime() {
+ return mSyncRunTimeSecs;
+ }
+
+ public static final Creator<SyncRequest> CREATOR = new Creator<SyncRequest>() {
+
+ @Override
+ public SyncRequest createFromParcel(Parcel in) {
+ return new SyncRequest(in);
+ }
+
+ @Override
+ public SyncRequest[] newArray(int size) {
+ return new SyncRequest[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeBundle(mExtras);
+ parcel.writeLong(mSyncFlexTimeSecs);
+ parcel.writeLong(mSyncRunTimeSecs);
+ parcel.writeInt((mIsPeriodic ? 1 : 0));
+ parcel.writeInt((mAllowMetered ? 1 : 0));
+ parcel.writeLong(mTxBytes);
+ parcel.writeLong(mRxBytes);
+ parcel.writeInt((mIsAuthority ? 1 : 0));
+ parcel.writeInt((mIsExpedited? 1 : 0));
+ if (mIsAuthority) {
+ parcel.writeParcelable(mAccountToSync, flags);
+ parcel.writeString(mAuthority);
+ } else {
+ parcel.writeParcelable(mComponentInfo, flags);
+ }
+ }
+
+ private SyncRequest(Parcel in) {
+ mExtras = in.readBundle();
+ mSyncFlexTimeSecs = in.readLong();
+ mSyncRunTimeSecs = in.readLong();
+ mIsPeriodic = (in.readInt() != 0);
+ mAllowMetered = (in.readInt() != 0);
+ mTxBytes = in.readLong();
+ mRxBytes = in.readLong();
+ mIsAuthority = (in.readInt() != 0);
+ mIsExpedited = (in.readInt() != 0);
+ if (mIsAuthority) {
+ mComponentInfo = null;
+ mAccountToSync = in.readParcelable(null);
+ mAuthority = in.readString();
+ } else {
+ mComponentInfo = in.readParcelable(null);
+ mAccountToSync = null;
+ mAuthority = null;
+ }
+ }
+
+ /** {@hide} Protected ctor to instantiate anonymous SyncRequest. */
+ protected SyncRequest(SyncRequest.Builder b) {
+ mSyncFlexTimeSecs = b.mSyncFlexTimeSecs;
+ mSyncRunTimeSecs = b.mSyncRunTimeSecs;
+ mAccountToSync = b.mAccount;
+ mAuthority = b.mAuthority;
+ mComponentInfo = b.mComponentName;
+ mIsPeriodic = (b.mSyncType == Builder.SYNC_TYPE_PERIODIC);
+ mIsAuthority = (b.mSyncTarget == Builder.SYNC_TARGET_ADAPTER);
+ mIsExpedited = b.mExpedited;
+ mExtras = new Bundle(b.mCustomExtras);
+ mAllowMetered = b.mAllowMetered;
+ mTxBytes = b.mTxBytes;
+ mRxBytes = b.mRxBytes;
+ }
+
+ /**
+ * Builder class for a @link SyncRequest. As you build your SyncRequest this class will also
+ * perform validation.
+ */
+ public static class Builder {
+ /** Unknown sync type. */
+ private static final int SYNC_TYPE_UNKNOWN = 0;
+ /** Specify that this is a periodic sync. */
+ private static final int SYNC_TYPE_PERIODIC = 1;
+ /** Specify that this is a one-time sync. */
+ private static final int SYNC_TYPE_ONCE = 2;
+ /** Unknown sync target. */
+ private static final int SYNC_TARGET_UNKNOWN = 0;
+ /** Specify that this is an anonymous sync. */
+ private static final int SYNC_TARGET_SERVICE = 1;
+ /** Specify that this is a sync with a provider. */
+ private static final int SYNC_TARGET_ADAPTER = 2;
+ /**
+ * Earliest point of displacement into the future at which this sync can
+ * occur.
+ */
+ private long mSyncFlexTimeSecs;
+ /** Displacement into the future at which this sync must occur. */
+ private long mSyncRunTimeSecs;
+ /**
+ * Sync configuration information - custom user data explicitly provided by the developer.
+ * This data is handed over to the sync operation.
+ */
+ private Bundle mCustomExtras;
+ /**
+ * Sync system configuration - used to store system sync configuration. Corresponds to
+ * ContentResolver.SYNC_EXTRAS_* flags.
+ * TODO: Use this instead of dumping into one bundle. Need to decide if these flags should
+ * discriminate between equivalent syncs.
+ */
+ private Bundle mSyncConfigExtras;
+ /** Expected upload transfer in bytes. */
+ private long mTxBytes = -1L;
+ /** Expected download transfer in bytes. */
+ private long mRxBytes = -1L;
+ /** Whether or not this sync can occur on metered networks. Default false. */
+ private boolean mAllowMetered;
+ /** Priority of this sync relative to others from calling app [-2, 2]. Default 0. */
+ private int mPriority = 0;
+ /**
+ * Whether this builder is building a periodic sync, or a one-time sync.
+ */
+ private int mSyncType = SYNC_TYPE_UNKNOWN;
+ /** Whether this will go to a sync adapter or to a sync service. */
+ private int mSyncTarget = SYNC_TARGET_UNKNOWN;
+ /** Whether this is a user-activated sync. */
+ private boolean mIsManual;
+ /**
+ * Whether to retry this one-time sync if the sync fails. Not valid for
+ * periodic syncs. See {@link ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY}.
+ */
+ private boolean mNoRetry;
+ /**
+ * Whether to respect back-off for this one-time sync. Not valid for
+ * periodic syncs. See
+ * {@link android.content.ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF};
+ */
+ private boolean mIgnoreBackoff;
+
+ /** Ignore sync system settings and perform sync anyway. */
+ private boolean mIgnoreSettings;
+
+ /** This sync will run in preference to other non-expedited syncs. */
+ private boolean mExpedited;
+
+ /**
+ * The @link android.content.AnonymousSyncService component that
+ * contains the sync logic if this is a provider-less sync, otherwise
+ * null.
+ */
+ private ComponentName mComponentName;
+ /**
+ * The Account object that together with an Authority name define the SyncAdapter (if
+ * this sync is bound to a provider), otherwise null. This gets resolved
+ * against a {@link com.android.server.content.SyncStorageEngine}.
+ */
+ private Account mAccount;
+ /**
+ * The Authority name that together with an Account define the SyncAdapter (if
+ * this sync is bound to a provider), otherwise null. This gets resolved
+ * against a {@link com.android.server.content.SyncStorageEngine}.
+ */
+ private String mAuthority;
+
+ public Builder() {
+ }
+
+ /**
+ * Developer can define timing constraints for this one-shot request.
+ * These values are elapsed real-time.
+ *
+ * @param whenSeconds The time in seconds at which you want this
+ * sync to occur.
+ * @param beforeSeconds The amount of time in advance of whenSeconds that this
+ * sync may be permitted to occur. This is rounded up to a minimum of 5
+ * seconds, for any sync for which whenSeconds > 5.
+ *
+ * Example
+ * <pre>
+ * Perform an immediate sync.
+ * SyncRequest.Builder builder = (new SyncRequest.Builder()).syncOnce(0, 0);
+ * That is, a sync 0 seconds from now with 0 seconds of flex.
+ *
+ * Perform a sync in exactly 5 minutes.
+ * SyncRequest.Builder builder =
+ * new SyncRequest.Builder().syncOnce(5 * MIN_IN_SECS, 0);
+ *
+ * Perform a sync in 5 minutes, with one minute of leeway (between 4 and 5 minutes from
+ * now).
+ * SyncRequest.Builder builder =
+ * new SyncRequest.Builder().syncOnce(5 * MIN_IN_SECS, 1 * MIN_IN_SECS);
+ * </pre>
+ */
+ public Builder syncOnce(long whenSeconds, long beforeSeconds) {
+ if (mSyncType != SYNC_TYPE_UNKNOWN) {
+ throw new IllegalArgumentException("Sync type has already been defined.");
+ }
+ mSyncType = SYNC_TYPE_ONCE;
+ setupInterval(whenSeconds, beforeSeconds);
+ return this;
+ }
+
+ /**
+ * Build a periodic sync. Either this or syncOnce() <b>must</b> be called for this builder.
+ * Syncs are identified by target {@link SyncService}/{@link android.provider} and by the
+ * contents of the extras bundle.
+ * You cannot reuse the same builder for one-time syncs after having specified a periodic
+ * sync (by calling this function). If you do, an {@link IllegalArgumentException} will be
+ * thrown.
+ *
+ * Example usage.
+ *
+ * <pre>
+ * Request a periodic sync every 5 hours with 20 minutes of flex.
+ * SyncRequest.Builder builder =
+ * (new SyncRequest.Builder()).syncPeriodic(5 * HOUR_IN_SECS, 20 * MIN_IN_SECS);
+ *
+ * Schedule a periodic sync every hour at any point in time during that hour.
+ * SyncRequest.Builder builder =
+ * (new SyncRequest.Builder()).syncPeriodic(1 * HOUR_IN_SECS, 1 * HOUR_IN_SECS);
+ * </pre>
+ *
+ * N.B.: Periodic syncs are not allowed to have any of
+ * {@link #SYNC_EXTRAS_DO_NOT_RETRY},
+ * {@link #SYNC_EXTRAS_IGNORE_BACKOFF},
+ * {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
+ * {@link #SYNC_EXTRAS_INITIALIZE},
+ * {@link #SYNC_EXTRAS_FORCE},
+ * {@link #SYNC_EXTRAS_EXPEDITED},
+ * {@link #SYNC_EXTRAS_MANUAL}
+ * set to true. If any are supplied then an {@link IllegalArgumentException} will
+ * be thrown.
+ *
+ * @param pollFrequency the amount of time in seconds that you wish
+ * to elapse between periodic syncs.
+ * @param beforeSeconds the amount of flex time in seconds before
+ * {@code pollFrequency} that you permit for the sync to take
+ * place. Must be less than {@code pollFrequency}.
+ */
+ public Builder syncPeriodic(long pollFrequency, long beforeSeconds) {
+ if (mSyncType != SYNC_TYPE_UNKNOWN) {
+ throw new IllegalArgumentException("Sync type has already been defined.");
+ }
+ mSyncType = SYNC_TYPE_PERIODIC;
+ setupInterval(pollFrequency, beforeSeconds);
+ return this;
+ }
+
+ /** {@hide} */
+ private void setupInterval(long at, long before) {
+ if (before > at) {
+ throw new IllegalArgumentException("Specified run time for the sync must be" +
+ " after the specified flex time.");
+ }
+ mSyncRunTimeSecs = at;
+ mSyncFlexTimeSecs = before;
+ }
+
+ /**
+ * Developer can provide insight into their payload size; optional. -1 specifies
+ * unknown, so that you are not restricted to defining both fields.
+ *
+ * @param rxBytes Bytes expected to be downloaded.
+ * @param txBytes Bytes expected to be uploaded.
+ */
+ public Builder setTransferSize(long rxBytes, long txBytes) {
+ mRxBytes = rxBytes;
+ mTxBytes = txBytes;
+ return this;
+ }
+
+ /**
+ * @param allow false to allow this transfer on metered networks.
+ * Default true.
+ */
+ public Builder setAllowMetered(boolean allow) {
+ mAllowMetered = true;
+ return this;
+ }
+
+ /**
+ * Give ourselves a concrete way of binding. Use an explicit
+ * authority+account SyncAdapter for this transfer, otherwise we bind
+ * anonymously to given componentname.
+ *
+ * @param authority
+ * @param account Account to sync. Can be null unless this is a periodic
+ * sync, for which verification by the ContentResolver will
+ * fail. If a sync is performed without an account, the
+ */
+ public Builder setSyncAdapter(Account account, String authority) {
+ if (mSyncTarget != SYNC_TARGET_UNKNOWN) {
+ throw new IllegalArgumentException("Sync target has already been defined.");
+ }
+ mSyncTarget = SYNC_TARGET_ADAPTER;
+ mAccount = account;
+ mAuthority = authority;
+ mComponentName = null;
+ return this;
+ }
+
+ /**
+ * Set Service component name for anonymous sync. This is not validated
+ * until sync time so providing an incorrect component name here will
+ * not fail.
+ *
+ * @param cname ComponentName to identify your Anonymous service
+ */
+ public Builder setSyncAdapter(ComponentName cname) {
+ if (mSyncTarget != SYNC_TARGET_UNKNOWN) {
+ throw new IllegalArgumentException("Sync target has already been defined.");
+ }
+ mSyncTarget = SYNC_TARGET_SERVICE;
+ mComponentName = cname;
+ mAccount = null;
+ mAuthority = null;
+ return this;
+ }
+
+ /**
+ * Developer-provided extras handed back when sync actually occurs. This bundle is copied
+ * into the SyncRequest returned by build().
+ *
+ * Example:
+ * <pre>
+ * String[] syncItems = {"dog", "cat", "frog", "child"};
+ * SyncRequest.Builder builder =
+ * new SyncRequest.Builder()
+ * .setSyncAdapter(dummyAccount, dummyProvider)
+ * .syncOnce(5 * MINUTES_IN_SECS);
+ *
+ * for (String syncData : syncItems) {
+ * Bundle extras = new Bundle();
+ * extras.setString("data", syncData);
+ * builder.setExtras(extras);
+ * ContentResolver.sync(builder.build()); // Each sync() request creates a unique sync.
+ * }
+ * </pre>
+ *
+ * Only values of the following types may be used in the extras bundle:
+ * <ul>
+ * <li>Integer</li>
+ * <li>Long</li>
+ * <li>Boolean</li>
+ * <li>Float</li>
+ * <li>Double</li>
+ * <li>String</li>
+ * <li>Account</li>
+ * <li>null</li>
+ * </ul>
+ * If any data is present in the bundle not of this type, build() will
+ * throw a runtime exception.
+ *
+ * @param bundle
+ */
+ public Builder setExtras(Bundle bundle) {
+ mCustomExtras = bundle;
+ return this;
+ }
+
+ /**
+ * Convenience function for setting {@link ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY}. A
+ * one-off sync operation that fails will be retried at a later date unless this is
+ * set to false. Default is true. Not valid for periodic sync and will throw an
+ * IllegalArgumentException in Builder.build().
+ *
+ * @param retry false to not retry a failed sync. Default true.
+ */
+ public Builder setNoRetry(boolean retry) {
+ mNoRetry = retry;
+ return this;
+ }
+
+ /**
+ * {@link ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS}. Not valid for
+ * periodic sync and will throw an IllegalArgumentException in
+ * Builder.build(). Default false.
+ */
+ public Builder setIgnoreSettings(boolean ignoreSettings) {
+ mIgnoreSettings = ignoreSettings;
+ return this;
+ }
+
+ /**
+ * Convenience function for setting {@link ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF}.
+ *
+ * @param ignoreBackoff
+ */
+ public Builder setIgnoreBackoff(boolean ignoreBackoff) {
+ mIgnoreBackoff = ignoreBackoff;
+ return this;
+ }
+
+ /**
+ * {@link ContentResolver.SYNC_EXTRAS_MANUAL}. Default false.
+ */
+ public Builder setManual(boolean isManual) {
+ mIsManual = isManual;
+ return this;
+ }
+
+ /**
+ * {@link ContentResolver.SYNC_EXTRAS_} Default false.
+ */
+ public Builder setExpedited(boolean expedited) {
+ mExpedited = expedited;
+ return this;
+ }
+
+ /**
+ * Priority of this request among all requests from the calling app.
+ * Range of [-2,2] similar to {@link android.app.Notification.priority}.
+ */
+ public Builder setPriority(int priority) {
+ if (priority < -2 || priority > 2) {
+ throw new IllegalArgumentException("Priority must be within range [-2, 2]");
+ }
+ mPriority = priority;
+ return this;
+ }
+
+ /**
+ * Performs validation over the request and throws the runtime exception
+ * IllegalArgumentException if this validation fails. TODO: Add
+ * validation of SyncRequest here. 1) Cannot specify both periodic &
+ * one-off (fails above). 2) Cannot specify both service and
+ * account/provider (fails above).
+ *
+ * @return a SyncRequest with the information contained within this
+ * builder.
+ */
+ public SyncRequest build() {
+ // Validate the extras bundle
+ try {
+ ContentResolver.validateSyncExtrasBundle(mCustomExtras);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ if (mCustomExtras == null) {
+ mCustomExtras = new Bundle();
+ }
+ // Combine the builder extra flags into the copy of the bundle.
+ if (mIgnoreBackoff) {
+ mCustomExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
+ }
+ if (mAllowMetered) {
+ mCustomExtras.putBoolean(ContentResolver.SYNC_EXTRAS_ALLOW_METERED, true);
+ }
+ if (mIgnoreSettings) {
+ mCustomExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+ }
+ if (mNoRetry) {
+ mCustomExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true);
+ }
+ if (mExpedited) {
+ mCustomExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ }
+ if (mIsManual) {
+ mCustomExtras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ }
+ // Upload/download expectations.
+ mCustomExtras.putLong(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD, mTxBytes);
+ mCustomExtras.putLong(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD, mRxBytes);
+ // Priority.
+ mCustomExtras.putInt(ContentResolver.SYNC_EXTRAS_PRIORITY, mPriority);
+ if (mSyncType == SYNC_TYPE_PERIODIC) {
+ // If this is a periodic sync ensure than invalid extras were
+ // not set.
+ if (mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
+ || mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
+ || mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
+ || mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
+ || mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
+ || mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
+ || mCustomExtras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
+ throw new IllegalArgumentException("Illegal extras were set");
+ }
+ } else if (mSyncType == SYNC_TYPE_UNKNOWN) {
+ throw new IllegalArgumentException("Must call either syncOnce() or syncPeriodic()");
+ }
+ // Ensure that a target for the sync has been set.
+ if (mSyncTarget == SYNC_TARGET_UNKNOWN) {
+ throw new IllegalArgumentException("Must specify an adapter with one of"
+ + "setSyncAdapter(ComponentName) or setSyncAdapter(Account, String");
+ }
+ return new SyncRequest(this);
+ }
+ }
+}
diff --git a/core/java/android/content/SyncResult.java b/core/java/android/content/SyncResult.java
index 6cb0d02..4f86af9 100644
--- a/core/java/android/content/SyncResult.java
+++ b/core/java/android/content/SyncResult.java
@@ -181,7 +181,7 @@
* <li> {@link SyncStats#numIoExceptions} > 0
* <li> {@link #syncAlreadyInProgress}
* </ul>
- * @return true if a hard error is indicated
+ * @return true if a soft error is indicated
*/
public boolean hasSoftError() {
return syncAlreadyInProgress || stats.numIoExceptions > 0;
@@ -195,6 +195,11 @@
return hasSoftError() || hasHardError();
}
+ /**
+ * Convenience method for determining if the Sync should be rescheduled after failing for some
+ * reason.
+ * @return true if the SyncManager should reschedule this sync.
+ */
public boolean madeSomeProgress() {
return ((stats.numDeletes > 0) && !tooManyDeletions)
|| stats.numInserts > 0
diff --git a/core/java/android/content/SyncService.java b/core/java/android/content/SyncService.java
new file mode 100644
index 0000000..100fd40
--- /dev/null
+++ b/core/java/android/content/SyncService.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.app.Service;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.Trace;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.HashMap;
+
+/**
+ * Simplified @link android.content.AbstractThreadedSyncAdapter. Folds that
+ * behaviour into a service to which the system can bind when requesting an
+ * anonymous (providerless/accountless) sync.
+ * <p>
+ * In order to perform an anonymous sync operation you must extend this service,
+ * implementing the abstract methods. This service must then be declared in the
+ * application's manifest as usual. You can use this service for other work, however you
+ * <b> must not </b> override the onBind() method unless you know what you're doing,
+ * which limits the usefulness of this service for other work.
+ *
+ * <pre>
+ * <service ndroid:name=".MyAnonymousSyncService" android:permission="android.permission.SYNC" />
+ * </pre>
+ * Like @link android.content.AbstractThreadedSyncAdapter this service supports
+ * multiple syncs at the same time. Each incoming startSync() with a unique tag
+ * will spawn a thread to do the work of that sync. If startSync() is called
+ * with a tag that already exists, a SyncResult.ALREADY_IN_PROGRESS is returned.
+ * Remember that your service will spawn multiple threads if you schedule multiple syncs
+ * at once, so if you mutate local objects you must ensure synchronization.
+ */
+public abstract class SyncService extends Service {
+
+ /** SyncAdapter Instantiation that any anonymous syncs call. */
+ private final AnonymousSyncAdapterImpl mSyncAdapter = new AnonymousSyncAdapterImpl();
+
+ /** Keep track of on-going syncs, keyed by tag. */
+ @GuardedBy("mLock")
+ private final HashMap<Bundle, AnonymousSyncThread>
+ mSyncThreads = new HashMap<Bundle, AnonymousSyncThread>();
+ /** Lock object for accessing the SyncThreads HashMap. */
+ private final Object mSyncThreadLock = new Object();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mSyncAdapter.asBinder();
+ }
+
+ /** {@hide} */
+ private class AnonymousSyncAdapterImpl extends IAnonymousSyncAdapter.Stub {
+
+ @Override
+ public void startSync(ISyncContext syncContext, Bundle extras) {
+ // Wrap the provided Sync Context because it may go away by the time
+ // we call it.
+ final SyncContext syncContextClient = new SyncContext(syncContext);
+ boolean alreadyInProgress = false;
+ synchronized (mSyncThreadLock) {
+ if (mSyncThreads.containsKey(extras)) {
+ // Don't want to call back to SyncManager while still
+ // holding lock.
+ alreadyInProgress = true;
+ } else {
+ AnonymousSyncThread syncThread = new AnonymousSyncThread(
+ syncContextClient, extras);
+ mSyncThreads.put(extras, syncThread);
+ syncThread.start();
+ }
+ }
+ if (alreadyInProgress) {
+ syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS);
+ }
+ }
+
+ /**
+ * Used by the SM to cancel a specific sync using the {@link
+ * com.android.server.content.SyncManager.ActiveSyncContext} as a handle.
+ */
+ @Override
+ public void cancelSync(ISyncContext syncContext) {
+ AnonymousSyncThread runningSync = null;
+ synchronized (mSyncThreadLock) {
+ for (AnonymousSyncThread thread : mSyncThreads.values()) {
+ if (thread.mSyncContext.getSyncContextBinder() == syncContext.asBinder()) {
+ runningSync = thread;
+ break;
+ }
+ }
+ }
+ if (runningSync != null) {
+ runningSync.interrupt();
+ }
+ }
+ }
+
+ /**
+ * {@hide}
+ * Similar to {@link android.content.AbstractThreadedSyncAdapter.SyncThread}. However while
+ * the ATSA considers an already in-progress sync to be if the account provided is currently
+ * syncing, this anonymous sync has no notion of account and therefore considers a sync unique
+ * if the provided bundle is different.
+ */
+ private class AnonymousSyncThread extends Thread {
+ private final SyncContext mSyncContext;
+ private final Bundle mExtras;
+
+ public AnonymousSyncThread(SyncContext syncContext, Bundle extras) {
+ mSyncContext = syncContext;
+ mExtras = extras;
+ }
+
+ @Override
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
+ Trace.traceBegin(Trace.TRACE_TAG_SYNC_MANAGER, getApplication().getPackageName());
+
+ SyncResult syncResult = new SyncResult();
+ try {
+ if (isCancelled()) {
+ return;
+ }
+ // Run the sync based off of the provided code.
+ SyncService.this.onPerformSync(mExtras, syncResult);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_SYNC_MANAGER);
+ if (!isCancelled()) {
+ mSyncContext.onFinished(syncResult);
+ }
+ // Synchronize so that the assignment will be seen by other
+ // threads
+ // that also synchronize accesses to mSyncThreads.
+ synchronized (mSyncThreadLock) {
+ mSyncThreads.remove(mExtras);
+ }
+ }
+ }
+
+ private boolean isCancelled() {
+ return Thread.currentThread().isInterrupted();
+ }
+ }
+
+ /**
+ * Initiate an anonymous sync using this service. SyncAdapter-specific
+ * parameters may be specified in extras, which is guaranteed to not be
+ * null.
+ */
+ public abstract void onPerformSync(Bundle extras, SyncResult syncResult);
+
+}
diff --git a/core/java/android/hardware/photography/ICameraDeviceUser.aidl b/core/java/android/hardware/photography/ICameraDeviceUser.aidl
index 1e58bab..571f50a 100644
--- a/core/java/android/hardware/photography/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/photography/ICameraDeviceUser.aidl
@@ -43,4 +43,6 @@
int createDefaultRequest(int templateId, out CameraMetadata request);
int getCameraInfo(out CameraMetadata info);
+
+ int waitUntilIdle();
}
diff --git a/core/java/android/hardware/photography/impl/CameraDevice.java b/core/java/android/hardware/photography/impl/CameraDevice.java
index 802cb833..5cb7525 100644
--- a/core/java/android/hardware/photography/impl/CameraDevice.java
+++ b/core/java/android/hardware/photography/impl/CameraDevice.java
@@ -65,9 +65,6 @@
return mCallbacks;
}
- /**
- * @hide
- */
public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
mRemoteDevice = remoteDevice;
}
@@ -209,7 +206,22 @@
@Override
public void waitUntilIdle() throws CameraAccessException {
- // TODO: implement
+
+ synchronized (mLock) {
+ checkIfCameraClosed();
+ if (!mRepeatingRequestIdStack.isEmpty()) {
+ throw new IllegalStateException("Active repeating request ongoing");
+ }
+
+ try {
+ mRemoteDevice.waitUntilIdle();
+ } catch (CameraRuntimeException e) {
+ throw e.asChecked();
+ } catch (RemoteException e) {
+ // impossible
+ return;
+ }
+ }
}
@Override
@@ -329,4 +341,9 @@
}
+ private void checkIfCameraClosed() {
+ if (mRemoteDevice == null) {
+ throw new IllegalStateException("CameraDevice was already closed");
+ }
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 188ddf2..555e883 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4588,6 +4588,10 @@
/**
* Called internally by the view system when a new view is getting focus.
* This is what clears the old focus.
+ * <p>
+ * <b>NOTE:</b> The parent view's focused child must be updated manually
+ * after calling this method. Otherwise, the view hierarchy may be left in
+ * an inconstent state.
*/
void unFocus() {
if (DBG) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 075719c..1f7ff9b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3250,24 +3250,23 @@
}
private boolean enterTouchMode() {
- if (mView != null) {
- if (mView.hasFocus()) {
- // note: not relying on mFocusedView here because this could
- // be when the window is first being added, and mFocused isn't
- // set yet.
- final View focused = mView.findFocus();
- if (focused != null && !focused.isFocusableInTouchMode()) {
- final ViewGroup ancestorToTakeFocus =
- findAncestorToTakeFocusInTouchMode(focused);
- if (ancestorToTakeFocus != null) {
- // there is an ancestor that wants focus after its descendants that
- // is focusable in touch mode.. give it focus
- return ancestorToTakeFocus.requestFocus();
- } else {
- // nothing appropriate to have focus in touch mode, clear it out
- focused.unFocus();
- return true;
- }
+ if (mView != null && mView.hasFocus()) {
+ // note: not relying on mFocusedView here because this could
+ // be when the window is first being added, and mFocused isn't
+ // set yet.
+ final View focused = mView.findFocus();
+ if (focused != null && !focused.isFocusableInTouchMode()) {
+ final ViewGroup ancestorToTakeFocus = findAncestorToTakeFocusInTouchMode(focused);
+ if (ancestorToTakeFocus != null) {
+ // there is an ancestor that wants focus after its
+ // descendants that is focusable in touch mode.. give it
+ // focus
+ return ancestorToTakeFocus.requestFocus();
+ } else {
+ // nothing appropriate to have focus in touch mode, clear it
+ // out
+ focused.clearFocus();
+ return true;
}
}
}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 77208b9..a8fef2d 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -156,18 +156,19 @@
// ----------------------------------------------------------------------------
static int
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
- jint source, jint sampleRateInHertz, jint channels,
+ jint source, jint sampleRateInHertz, jint channelMask,
+ // Java channel masks map directly to the native definition
jint audioFormat, jint buffSizeInBytes, jintArray jSession)
{
//ALOGV(">> Entering android_media_AudioRecord_setup");
- //ALOGV("sampleRate=%d, audioFormat=%d, channels=%x, buffSizeInBytes=%d",
- // sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
+ //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
+ // sampleRateInHertz, audioFormat, channelMask, buffSizeInBytes);
- if (!audio_is_input_channel(channels)) {
- ALOGE("Error creating AudioRecord: channel count is not 1 or 2.");
+ if (!audio_is_input_channel(channelMask)) {
+ ALOGE("Error creating AudioRecord: channel mask %#x is not valid.", channelMask);
return AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK;
}
- uint32_t nbChannels = popcount(channels);
+ uint32_t nbChannels = popcount(channelMask);
// compare the format against the Java constants
if ((audioFormat != javaAudioRecordFields.PCM16)
@@ -226,7 +227,7 @@
lpRecorder->set((audio_source_t) source,
sampleRateInHertz,
format, // word length, PCM
- channels,
+ channelMask,
frameCount,
recorderCallback,// callback_t
lpCallbackData,// void* user
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index a9a87d6..a1b85bc 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -218,7 +218,7 @@
uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
if (!audio_is_output_channel(nativeChannelMask)) {
- ALOGE("Error creating AudioTrack: invalid channel mask.");
+ ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
}
diff --git a/docs/html-intl/es/training/multiscreen/index.jd b/docs/html-intl/es/training/multiscreen/index.jd
index 0a1461b..d836f96 100644
--- a/docs/html-intl/es/training/multiscreen/index.jd
+++ b/docs/html-intl/es/training/multiscreen/index.jd
@@ -18,7 +18,7 @@
<li>Experiencia en el desarrollo de una <a
href="http://developer.android.com/guide/topics/ui/index.html">Interfaz de usuario</a> de Android</li>
<li>Algunas funciones requieren el uso de la <a
-href="{@docRoot}tools/extras/support-library.html">biblioteca de compatibilidad</a></li>
+href="{@docRoot}tools/support-library/index.html">biblioteca de compatibilidad</a></li>
</ul>
<h2>También puedes consultar:</h2>
@@ -46,7 +46,7 @@
<p>El código que aparece en cada sección se ha extraído de una aplicación de ejemplo para explicar las prácticas recomendadas a la hora de optimizar tu aplicación para varias pantallas. Puedes descargar el ejemplo (situado a la derecha) y utilizarlo como fuente de código reutilizable para tu propia aplicación.</p>
<p class="note"><strong>Nota:</strong> en esta sección y en el ejemplo correspondiente, se utiliza la <a
-href="{@docRoot}tools/extras/support-library.html">biblioteca de compatibilidad</a> para poder usar las API de <PH>{@link android.app.Fragment}</PH> en versiones anteriores a Android 3.0. Debes descargar y la biblioteca y añadirla a tu aplicación para poder utilizar todas las API que se indican en esta sección.</p>
+href="{@docRoot}tools/support-library/index.html">biblioteca de compatibilidad</a> para poder usar las API de <PH>{@link android.app.Fragment}</PH> en versiones anteriores a Android 3.0. Debes descargar y la biblioteca y añadirla a tu aplicación para poder utilizar todas las API que se indican en esta sección.</p>
<h2>Secciones</h2>
diff --git a/docs/html-intl/ja/training/multiscreen/index.jd b/docs/html-intl/ja/training/multiscreen/index.jd
index ff84f8a..9e01584 100644
--- a/docs/html-intl/ja/training/multiscreen/index.jd
+++ b/docs/html-intl/ja/training/multiscreen/index.jd
@@ -19,7 +19,7 @@
<li>Android <a
href="http://developer.android.com/guide/topics/ui/index.html">ユーザー インターフェース</a>の開発経験</li>
<li><a
-href="{@docRoot}tools/extras/support-library.html">サポート ライブラリ</a>の利用(一部の機能で必要)</li>
+href="{@docRoot}tools/support-library/index.html">サポート ライブラリ</a>の利用(一部の機能で必要)</li>
</ul>
<h2>関連ドキュメント</h2>
@@ -47,7 +47,7 @@
<p>各レッスンで紹介されているコードは、複数の画面に合わせて最適化する際、ベスト プラクティスとなるサンプル アプリから抜粋したものです。このサンプルを(右側から)ダウンロードして、再利用可能なコードのソースとしてご自分のアプリに使用することができます。</p>
<p class="note"><strong>注:</strong> このクラスと関連サンプルでは、<a
-href="{@docRoot}tools/extras/support-library.html">サポート ライブラリ</a>を使用します。理由は、Android 3.0 未満のバージョンで <PH>{@link android.app.Fragment}</PH> API を使用するためです。このクラスのすべての API を使用するには、ライブラリをダウンロードして、アプリに追加する必要があります。</p>
+href="{@docRoot}tools/support-library/index.html">サポート ライブラリ</a>を使用します。理由は、Android 3.0 未満のバージョンで <PH>{@link android.app.Fragment}</PH> API を使用するためです。このクラスのすべての API を使用するには、ライブラリをダウンロードして、アプリに追加する必要があります。</p>
<h2>レッスン</h2>
diff --git a/docs/html-intl/ko/training/multiscreen/index.jd b/docs/html-intl/ko/training/multiscreen/index.jd
index d9e09b0..dd152ae 100644
--- a/docs/html-intl/ko/training/multiscreen/index.jd
+++ b/docs/html-intl/ko/training/multiscreen/index.jd
@@ -19,7 +19,7 @@
<li>Android <a
href="http://developer.android.com/guide/topics/ui/index.html"> 사용자 인터페이스</a> 구축 경험</li>
<li><a
-href="{@docRoot}tools/extras/support-library.html">호환성 라이브러리</a>를 사용해야 하는 여러 기능</li>
+href="{@docRoot}tools/support-library/index.html">호환성 라이브러리</a>를 사용해야 하는 여러 기능</li>
</ul>
<h2>참고자료</h2>
@@ -47,7 +47,7 @@
<p>각 강의에서 사용되는 코드는 여러 화면에 대한 최적화의 모범 사례를 보여주는 샘플 애플리케이션에서 가져온 것입니다. 샘플(오른쪽)을 다운로드하여 본인의 애플리케이션에 코드로 재사용할 수 있습니다. </p>
<p class="note"><strong>참고:</strong> 이 강의 및 강의와 관련된 샘플은 <a
-href="{@docRoot}tools/extras/support-library.html">호환성 라이브러리</a>를 사용하며 이는 Android 3.0 이하 버전에서 <PH>{@link android.app.Fragment}</PH> API를 사용하기 위해서입니다. 이 강의에서 API를 모두 사용하려면 라이브러리를 다운로드하여 애플리케이션에 추가해야 합니다.</p>
+href="{@docRoot}tools/support-library/index.html">호환성 라이브러리</a>를 사용하며 이는 Android 3.0 이하 버전에서 <PH>{@link android.app.Fragment}</PH> API를 사용하기 위해서입니다. 이 강의에서 API를 모두 사용하려면 라이브러리를 다운로드하여 애플리케이션에 추가해야 합니다.</p>
<h2>강의</h2>
diff --git a/docs/html-intl/ru/training/multiscreen/index.jd b/docs/html-intl/ru/training/multiscreen/index.jd
index 023eaec..84b9b8b 100644
--- a/docs/html-intl/ru/training/multiscreen/index.jd
+++ b/docs/html-intl/ru/training/multiscreen/index.jd
@@ -19,7 +19,7 @@
<li>Опыт создания <a
href="http://developer.android.com/guide/topics/ui/index.html">пользовательских интерфейсов</a> для Android</li>
<li>Некоторые функции требуют использования <a
-href="{@docRoot}tools/extras/support-library.html">вспомогательной библиотеки</a></li>
+href="{@docRoot}tools/support-library/index.html">вспомогательной библиотеки</a></li>
</ul>
<h2>Дополнительные материалы</h2>
@@ -47,7 +47,7 @@
<p>Код, приведенный в каждом уроке, взят из учебного приложения, в котором демонстрируются способы оптимизации для разных экранов. Вы можете загрузить его (в правой части экрана) и использовать части кода в собственном приложении.</p>
<p class="note"><strong>Примечание</strong>. В этом модуле и в учебном приложении используется <a
-href="{@docRoot}tools/extras/support-library.html">вспомогательная библиотека</a>, позволяющая работать с API <PH>{@link android.app.Fragment}</PH> в версиях до Android 3.0. Чтобы иметь возможность использовать все необходимые API, загрузите библиотеку и добавьте ее в свое приложение.</p>
+href="{@docRoot}tools/support-library/index.html">вспомогательная библиотека</a>, позволяющая работать с API <PH>{@link android.app.Fragment}</PH> в версиях до Android 3.0. Чтобы иметь возможность использовать все необходимые API, загрузите библиотеку и добавьте ее в свое приложение.</p>
<h2>Уроки</h2>
diff --git a/docs/html-intl/zh-cn/training/multiscreen/index.jd b/docs/html-intl/zh-cn/training/multiscreen/index.jd
index 35c48e0..3514bd6 100644
--- a/docs/html-intl/zh-cn/training/multiscreen/index.jd
+++ b/docs/html-intl/zh-cn/training/multiscreen/index.jd
@@ -19,7 +19,7 @@
<li>构建 Android <a
href="http://developer.android.com/guide/topics/ui/index.html">用户界面</a>的经验</li>
<li>多个功能需要用到<a
-href="{@docRoot}tools/extras/support-library.html">支持库</a></li>
+href="{@docRoot}tools/support-library/index.html">支持库</a></li>
</ul>
<h2>您还应参阅</h2>
@@ -47,7 +47,7 @@
<p>各教程中都提及了一种来自一个示例应用的代码,该应用展示了关于针对多种分辨率进行优化的最佳实践。您可以在右侧下载该示例,并在自己的应用内重复使用其中的代码。</p>
<p class="note"><strong>请注意</strong>:本教程和相关的示例使用了<a
-href="{@docRoot}tools/extras/support-library.html">支持库</a>,以便在 3.0 版以下的 Android 上使用 <PH>{@link android.app.Fragment}</PH> API。因此,您需要下载该库并将其添加到您的应用,才能使用本教程中涉及的所有 API。</p>
+href="{@docRoot}tools/support-library/index.html">支持库</a>,以便在 3.0 版以下的 Android 上使用 <PH>{@link android.app.Fragment}</PH> API。因此,您需要下载该库并将其添加到您的应用,才能使用本教程中涉及的所有 API。</p>
<h2>教程</h2>
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 27cedcb..2169c8e 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -19,7 +19,7 @@
to: /sdk/exploring.html
- from: /sdk/compatibility-library.html
- to: /tools/extras/support-library.html
+ to: /tools/support-library/index.html
- from: /sdk/eclipse-adt.html
to: /tools/sdk/eclipse-adt.html
diff --git a/docs/html/about/versions/android-4.0.jd b/docs/html/about/versions/android-4.0.jd
index 1ce005d..2fa180c 100644
--- a/docs/html/about/versions/android-4.0.jd
+++ b/docs/html/about/versions/android-4.0.jd
@@ -822,7 +822,7 @@
<p>If you want to maintain compatibility with Android versions prior to 4.0, while also supporting
the new the accessibility APIs, you can do so with the latest version of the <em>v4 support
-library</em> (in <a href="{@docRoot}tools/extras/support-library.html">Compatibility Package, r4</a>)
+library</em> (in <a href="{@docRoot}tools/support-library/index.html">Compatibility Package, r4</a>)
using a set of utility classes that provide the new accessibility APIs in a backward-compatible
design.</p>
diff --git a/docs/html/about/versions/android-4.3.jd b/docs/html/about/versions/android-4.3.jd
index d0ccfbe..bccc9d5 100644
--- a/docs/html/about/versions/android-4.3.jd
+++ b/docs/html/about/versions/android-4.3.jd
@@ -36,7 +36,7 @@
</li>
<li><a href="#Multimedia">Multimedia</a>
<ol>
- <li><a href="#DASH">MPEG DASH support</a></li>
+ <li><a href="#MediaExtractor">MediaExtractor and MediaCodec enhancements</a></li>
<li><a href="#DRM">Media DRM</a></li>
<li><a href="#EncodingSurface">Video encoding from a Surface</a></li>
<li><a href="#MediaMuxing">Media muxing</a></li>
@@ -109,7 +109,7 @@
<li><a href="{@docRoot}sdk/api_diff/18/changes.html">API
Differences Report »</a> </li>
<li><a
-href="{@docRoot}tools/extras/support-library.html">Support Library</a></li>
+href="{@docRoot}tools/support-library/index.html">Support Library</a></li>
</ol>
</div>
@@ -150,7 +150,7 @@
Platform Versions</a>.</p>
<p>Various APIs are also available in the Android <a
-href="{@docRoot}tools/extras/support-library.html">Support Library</a> that allow you to implement
+href="{@docRoot}tools/support-library/index.html">Support Library</a> that allow you to implement
new features on older versions of the platform.</p>
<p>For more information about how API levels work, read <a
@@ -439,10 +439,11 @@
<h2 id="Multimedia">Multimedia</h2>
-<h3 id="DASH">MPEG DASH support</h3>
+<h3 id="MediaExtractor">MediaExtractor and MediaCodec enhancements</h3>
-<p>Android now supports Dynamic Adaptive Streaming over HTTP (DASH) in accordance with the
-ISO/IEC 23009-1 standard, using existing APIs in {@link android.media.MediaCodec} and {@link
+<p>Android now makes it easier for you to write your own Dynamic Adaptive
+Streaming over HTTP (DASH) players in accordance with the ISO/IEC 23009-1 standard,
+using existing APIs in {@link android.media.MediaCodec} and {@link
android.media.MediaExtractor}. The framework underlying these APIs has been updated to support
parsing of fragmented MP4 files, but your app is still responsible for parsing the MPD metadata
and passing the individual streams to {@link android.media.MediaExtractor}.</p>
@@ -584,7 +585,13 @@
</manifest>
</pre>
-<p>And remember to specify the OpenGL ES context by calling {@link android.opengl.GLSurfaceView#setEGLContextClientVersion setEGLContextClientVersion()}, passing {@code 3} as the version.</p>
+<p>And remember to specify the OpenGL ES context by calling {@link
+android.opengl.GLSurfaceView#setEGLContextClientVersion setEGLContextClientVersion()},
+passing {@code 3} as the version.</p>
+
+<p>For more information about using OpenGL ES, including how to check the device's supported
+OpenGL ES version at runtime, see the <a href="{@docRoot}guide/topics/graphics/opengl.html"
+>OpenGL ES</a> API guide.</p>
<h3 id="MipMap">Mipmapping for drawables</h3>
@@ -936,7 +943,7 @@
to {@link android.text.BidiFormatter#unicodeWrap(String,TextDirectionHeuristic) unicodeWrap()}.</p>
<p class="note"><strong>Note:</strong> These new APIs are also available for previous versions
-of Android through the Android <a href="{@docRoot}tools/extras/support-library.html">Support
+of Android through the Android <a href="{@docRoot}tools/support-library/index.html">Support
Library</a>, with the {@link android.support.v4.text.BidiFormatter} class and related APIs.</p>
@@ -974,7 +981,7 @@
<p class="note"><strong>Note:</strong> These new APIs are also available for previous versions
-of Android through the Android <a href="{@docRoot}tools/extras/support-library.html">Support
+of Android through the Android <a href="{@docRoot}tools/support-library/index.html">Support
Library</a>, with the {@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat}
class.</p>
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index 5812f3d..985a266 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -1,8 +1,10 @@
page.title=Jelly Bean
-tab1=Android 4.2
-tab1.link=#android-42
-tab2=Android 4.1
-tab2.link=#android-41
+tab1=Android 4.3
+tab1.link=#android-43
+tab2=Android 4.2
+tab2.link=#android-42
+tab3=Android 4.1
+tab3.link=#android-41
@jd:body
<div id="butterbar-wrapper" >
@@ -16,6 +18,7 @@
<style>
#android-41 {display:none;}
+#android-42 {display:none;}
</style>
<script>
@@ -60,6 +63,573 @@
</script>
+<!-- BEGIN ANDROID 4.3 -->
+<div id="android-43" class="version-section">
+
+<div style="float:right;padding:0px 0px 10px 28px;width:480px;">
+<div>
+<a href="{@docRoot}images/jb-android-43@2x.png"><img src="{@docRoot}images/jb-android-43.jpg" alt="Android 4.3 on phone and tablet" width="472"></a>
+
+</div>
+</div>
+<p>Welcome to Android 4.3, a sweeter version of <span
+style="white-space:nowrap;">Jelly Bean!</span></p>
+
+<p>Android 4.3 includes performance optimizations and great
+new features for users and developers. This document provides a glimpse of what's new for
+developers.
+
+<p>See the <a href="{@docRoot}about/versions/android-4.3.html">Android 4.3 APIs</a>
+document for a detailed look at the new developer APIs.</p>
+
+<p>Find out more about the new Jelly Bean features for users at <a
+href="http://www.android.com/whatsnew">www.android.com</a>.</p>
+
+
+<h2 id="43-performance" style="line-height:1.25em;">Faster, Smoother, More
+Responsive</h2>
+
+<p>Android 4.3 builds on the performance improvements already included in Jelly
+Bean — <strong>vsync timing</strong>, <strong>triple buffering</strong>,
+<strong>reduced touch latency</strong>, <strong>CPU input boost</strong>, and
+<strong>hardware-accelerated 2D rendering</strong> — and adds new
+optimizations that make Android even faster.</p>
+
+<p>For a graphics performance boost, the hardware-accelerated 2D renderer now
+<strong>optimizes the stream of drawing commands</strong>, transforming it into
+a more efficient GPU format by rearranging and merging draw operations. For
+multithreaded processing, the renderer can also now use <strong>multithreading
+across multiple CPU cores</strong> to perform certain tasks.</p>
+
+<p>Android 4.3 also improves <strong>rendering for shapes and text</strong>.
+Shapes such as circles and rounded rectangles are now rendered at higher quality
+in a more efficient manner. Optimizations for text include increased performance
+when using multiple fonts or complex glyph sets (CJK), higher rendering quality
+when scaling text, and faster rendering of drop shadows.</p>
+
+<p><strong>Improved window buffer allocation</strong> results in a faster image
+buffer allocation for your apps, reducing the time taken to start rendering when
+you create a window.</p>
+
+<p>For highest-performance graphics, Android 4.3 introduces support for
+<strong>OpenGL ES 3.0</strong> and makes it accessible to apps through both
+framework and native APIs. On supported devices, the hardware accelerated 2D
+rendering engine takes advantage of OpenGL ES 3.0 to optimize <strong>texture
+management</strong> and increase <strong>gradient rendering
+fidelity</strong>.</p>
+
+
+<h2 id="43-graphics">OpenGL ES 3.0 for High-Performance Graphics</h2>
+
+<p>Android 4.3 introduces platform support for <a class="external-link"
+href="http://www.khronos.org/opengles/3_X/" target="_android">Khronos OpenGL ES 3.0</a>,
+providing games and other apps with highest-performance 2D and 3D graphics
+capabilities on supported devices. You can take advantage of OpenGL ES 3.0
+and related EGL extensions using either <strong>framework APIs</strong>
+or <strong>native API bindings</strong> through the Android Native Development
+Kit (NDK).</p>
+
+<p>Key new functionality provided in OpenGL ES 3.0 includes acceleration of
+advanced visual effects, high quality ETC2/EAC texture compression as a standard
+feature, a new version of the GLSL ES shading language with integer and 32-bit
+floating point support, advanced texture rendering, and standardized texture
+size and render-buffer formats.
+
+<p>You can use the OpenGL ES 3.0 APIs to create highly complex, highly efficient
+graphics that run across a range of compatible Android devices, and you can
+support a single, standard texture-compression format across those devices.</p>
+
+<p>OpenGL ES 3.0 is an optional feature that depends on underlying graphics
+hardware. Support is already available on Nexus 7 (2013), Nexus 4, and
+Nexus 10 devices.</p>
+
+
+<h2 id="43-bluetooth" style="clear:both;">Enhanced Bluetooth Connectivity</h2>
+
+<h4 id="43-bt-le">Connectivity with Bluetooth Smart devices and sensors</h4>
+
+<p>Now you can design and build apps that interact with the latest generation
+of small, low-power devices and sensors that use <a
+href="http://www.bluetooth.com/Pages/Bluetooth-Smart-Devices.aspx"
+class="external-link" target="_android">Bluetooth Smart technology</a>. </p>
+
+<div style="float:right;margin:0px 0px 32px 0px;width:460px;">
+<img src="{@docRoot}images/jb-btle.png" alt="" width="450" style="padding-left:1.5em;margin-bottom:0">
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;margin-bottom:0;padding-left:1.5em;">Android 4.3 gives you a single, standard API for interacting with Bluetooth Smart devices. </p>
+</div>
+
+<p>Android 4.3 introduces built-in platform support for <strong>Bluetooth Smart
+Ready</strong> in the central role and provides a standard set of APIs that
+apps can use to discover nearby devices, query for GATT services, and read/write
+characteristics.</p>
+
+<p>With the new APIs, your apps can efficiently scan for devices and services of
+interest. For each device, you can check for supported GATT services by UUID and
+manage connections by device ID and signal strength. You can connect to a GATT
+server hosted on the device and read or write characteristics, or register a
+listener to receive notifications whenever those characteristics change.</p>
+
+<p>You can implement support for any GATT profile. You can read or write
+standard characteristics or add support for custom characteristics as needed.
+Your app can function as either client or server and can transmit and receive
+data in either mode. The APIs are generic, so you’ll be able to support
+interactions with a variety of devices such as proximity tags, watches, fitness
+meters, game controllers, remote controls, health devices, and more.
+</p>
+
+<p>Support for Bluetooth Smart Ready is already available on Nexus 7 (2013)
+and Nexus 4 devices and will be supported in a growing number of
+Android-compatible devices in the months ahead.</p>
+
+<h4 id="43-bt-avrcp">AVRCP 1.3 Profile</h4>
+
+<p>Android 4.3 adds built-in support for <strong>Bluetooth AVRCP 1.3</strong>,
+so your apps can support richer interactions with remote streaming media
+devices. Apps such as media players can take advantage of AVRCP 1.3 through the
+<strong>remote control client APIs</strong> introduced in Android 4.0. In
+addition to exposing playback controls on the remote devices connected over
+Bluetooth, apps can now transmit metadata such as track name, composer, and
+other types of media metadata. </p>
+
+<p>Platform support for AVRCP 1.3 is built on the Bluedroid Bluetooth stack
+introduced by Google and Broadcom in Android 4.2. Support is available right
+away on Nexus devices and other Android-compatible devices that offer A2DP/AVRCP
+capability. </p>
+
+
+<h2 id="43-profiles">Support for Restricted Profiles</h2>
+
+<div style="float:right;margin:22px 0px 0px 24px;width:340px;">
+<img src="{@docRoot}images/jb-profiles-create-n713.png" alt="Setting up a Restricted Profile" width="340" style="margin-bottom:0">
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;margin-bottom:0;">A tablet owner can set up one or more restricted profiles in Settings and manage them independently. </p>
+<img src="{@docRoot}images/jb-profiles-restrictions-n713.png" alt="Setting Restrictions in a Profile" width="340" style="margin-bottom:0;padding-top:1em;">
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">Your app can offer restrictions to let owners manage your app content when it's running in a profile. </p>
+</div>
+
+<p>Android 4.3 extends the multiuser feature for tablets with <strong>restricted
+profiles</strong>, a new way to manage users and their capabilities on a single
+device. With restricted profiles, tablet owners can quickly set up
+<strong>separate environments</strong> for each user, with the ability to
+manage <strong>finer-grained restrictions</strong> in the apps that are
+available in those environments. Restricted profiles are ideal for friends and
+family, guest users, kiosks, point-of-sale devices, and more. </p>
+
+<p>Each restricted profile offers an isolated and secure space with its own
+local storage, home screens, widgets, and settings. Unlike with
+users, profiles are created from the tablet owner’s environment, based on the
+owner’s installed apps and system accounts. The owner controls which installed
+apps are enabled in the new profile, and access to the owner’s accounts is
+disabled by default. </p>
+
+<p>Apps that need to access the owner’s accounts — for sign-in,
+preferences, or other uses — can opt-in by declaring a manifest attribute,
+and the owner can review and manage those apps from the profile configuration
+settings.</p>
+
+<p>For developers, restricted profiles offer a new way to deliver more value and
+control to your users. You can implement <strong>app restrictions</strong>
+— content or capabilities controls that are supported by your app —
+and advertise them to tablet owners in the profile configuration settings.
+</p>
+
+<p>You can add app restrictions directly to the profile configuration settings
+using predefined boolean, select, and multi-select types. If you want more
+flexibility, you can even launch your own UI from profile configuration settings
+to offer any type of restriction you want. </p>
+
+<p>When your app runs in a profile, it can check for any restrictions configured
+by the owner and enforce them appropriately. For example, a media app
+might offer a restriction to let the owner set a maturity level for the profile.
+At run time, the app could check for the maturity setting and then manage
+content according to the preferred maturity level. </p>
+
+<p>If your app is not designed for use in restricted profiles, you can opt
+out altogether, so that your app can't be enabled in any restricted profile.</p>
+
+
+<h2 id="43-optimized-location">Optimized Location and Sensor Capabilities</h2>
+
+<p><a href="{@docRoot}google/play-services/index.html">Google Play services</a>
+offers advanced location APIs that you can use in your apps. Android 4.3
+<strong>optimizes these APIs</strong> on supported devices with new hardware and
+software capabilities that minimize use of the battery. </p>
+
+
+<div style="float:left;margin:22px 24px 36px 22px;width:250px;">
+<a href=""><img src="{@docRoot}images/google/gps-location.png" alt="" height="160" style="padding-right:1.5em;margin-bottom:0"></a>
+</div>
+
+<p><strong>Hardware geofencing</strong> optimizes for power efficiency by
+performing location computation in the device hardware, rather than in
+software. On devices that support hardware geofencing, Google Play services
+geofence APIs will be able to take advantage of this optimization to save
+battery while the device is moving. </p>
+
+<p><strong>Wi-Fi scan-only mode</strong> is a new platform optimization that
+lets users keep Wi-Fi scan on without connecting to a Wi-Fi network, to improve
+location accuracy while conserving battery. Apps that depend on Wi-Fi for
+location services can now ask users to enable scan-only mode from Wi-Fi
+advanced settings. Wi-Fi scan-only mode is not dependent on device hardware and
+is available as part of the Android 4.3 platform.</p>
+
+<p>New sensor types allow apps to better manage sensor readings. A <strong>game
+rotation vector</strong> lets game developers sense the device’s rotation
+without having to worry about magnetic interference. <strong>Uncalibrated
+gyroscope</strong> and <strong>uncalibrated magnetometer</strong> sensors report
+raw measurements as well as estimated biases to apps. </p>
+
+<p>The new hardware capabilities are already available on Nexus 7 (2013) and
+Nexus 4 devices, and any device manufacturer or chipset vendor can build them
+into their devices.</p>
+
+
+<h2 id="43-media">New Media Capabilities</h2>
+
+<h4 id="43-modular-drm">Modular DRM framework</h4>
+
+<p>To meet the needs of the next generation of media services, Android 4.3
+introduces a <strong>modular DRM framework</strong> that enables media application
+developers to more easily integrate DRM into their own streaming protocols, such
+as MPEG DASH (Dynamic Adaptive Streaming over HTTP, ISO/IEC 23009-1).</p>
+
+<p>Through a combination of new APIs and enhancements to existing APIs, the
+media DRM framework provides an <strong>integrated set of services</strong> for
+managing licensing and provisioning, accessing low-level codecs, and decoding
+encrypted media data. A new MediaExtractor API lets you get the PSSH metadata
+for DASH media. Apps using the media DRM framework manage the network
+communication with a license server and handle the streaming of encrypted data
+from a content library. </p>
+
+<h4 id="43-vp8-encoder">VP8 encoder</h4>
+
+<p>Android 4.3 introduces built-in support for <strong>VP8 encoding</strong>,
+accessible from framework and native APIs. For apps using native APIs, the
+platform includes <strong>OpenMAX 1.1.2 extension headers</strong> to support
+VP8 profiles and levels. VP8 encoding support includes settings for target
+bitrate, rate control, frame rate, token partitioning, error resilience,
+reconstruction and loop filters. The platform API introduces VP8 encoder support
+in a range of formats, so you can take advantage of the best format for your
+content. </p>
+
+<p>VP8 encoding is available in software on all compatible devices running
+Android 4.3. For highest performance, the platform also supports
+hardware-accelerated VP8 encoding on capable devices.</p>
+
+<h4 id="43-surface">Video encoding from a surface</h4>
+
+<p>Starting in Android 4.3 you can use a surface as the input to a video
+encoder. For example, you can now direct a stream from an OpenGL ES surface
+to the encoder, rather than having to copy between buffers.</p>
+
+<h4 id="43-media-muxer">Media muxer</h4>
+
+<p>Apps can use new media muxer APIs to combine elementary audio and video
+streams into a single output file. Currently apps can multiplex a single MPEG-4
+audio stream and a single MPEG-4 video stream into a <strong>single MPEG-4 ouput
+file</strong>. The new APIs are a counterpart to the media demuxing APIs
+introduced in Android 4.2. </p>
+
+<h4 id="43-progress-scrubbing">Playback progress and scrubbing in remote control
+clients</h4>
+
+<p>Since Android 4.0, media players and similar applications have been able to
+offer playback controls from remote control clients such as the device lock
+screen, notifications, and remote devices connected over Bluetooth. Starting in
+Android 4.3, those applications can now also expose playback <strong>progress
+and speed</strong> through their remote control clients, and receive commands to
+jump to a specific <strong>playback position</strong>. </p>
+
+
+<h2 id="43-beautiful-apps">New Ways to Build Beautiful Apps</h2>
+
+
+<h3 id="43-notification-access">Access to notifications</h3>
+
+<p>Notifications have long been a popular Android feature because they let users
+see information and updates from across the system, all in one place. Now in
+Android 4.3, apps can <strong>observe the stream of notifications</strong> with the
+user's permission and display the notifications in any way they want, including
+sending them to nearby devices connected over Bluetooth. </p>
+
+<p>You can access notifications through new APIs that let you <strong>register a
+notification listener</strong> service and with permission of the user, receive
+notifications as they are displayed in the status bar. Notifications are
+delivered to you in full, with all details on the originating app, the post
+time, the content view and style, and priority. You can evaluate fields of
+interest in the notifications, process or add context from your app, and route
+them for display in any way you choose.</p>
+
+<p>The new API gives you callbacks when a notification is added, updated, and
+removed (either because the user dismissed it or the originating app withdrew it).
+You'll be able to launch any intents attached to the notification or its actions,
+as well as dismiss it from the system, allowing your app to provide a complete
+user interface to notifications.</p>
+
+<p><strong>Users remain in control</strong> of which apps can receive
+notifications. At any time, they can look in Settings to see which apps have
+notification access and <strong>enable or disable access</strong> as needed.
+Notification access is disabled by default — apps can use a new Intent to
+take the user directly to the Settings to enable the listener service after
+installation.</p>
+
+<h4 id="43-view-overlays">View overlays</h4>
+
+<p>You can now create <strong>transparent overlays</strong> on top of Views and
+ViewGroups to render a temporary View hierarchy or transient animation effects
+without disturbing the underlying layout hierarchy. Overlays are particularly
+useful when you want to create animations such as sliding a view outside of its
+container or dragging items on the screen without affecting the view
+hierarchy. </p>
+
+<h4 id="43-optical-bounds">Optical bounds layout mode</h4>
+
+<p>A new layout mode lets you manage the positioning of Views inside ViewGroups
+according to their <strong>optical bounds</strong>, rather than their clip
+bounds. Clip bounds represent a widget’s actual outer boundary, while the new
+optical bounds describe the where the widget appears to be, within the clip
+bounds. You can use the optical bounds layout mode to properly align widgets
+that use outer visual effects such as shadows and glows.</p>
+
+<h4 id="43-rotation-animation">Custom rotation animation types</h4>
+
+<p>Apps can now define the exit and entry animation types used on a window when the
+device is rotated. You can set window properties to enable
+<strong>jump-cut</strong>, <strong>cross-fade</strong>, or
+<strong>standard</strong> window rotation. The system uses the custom animation
+types when the window is fullscreen and is not covered by other windows.</p>
+
+<h4 id="43-screen-orientations">Screen orientation modes</h4>
+
+<p>Apps can set new orientation modes for Activities to ensure that they are
+displayed in the proper orientation when the device is flipped. Additionally,
+apps can use a new mode to <strong>lock the screen</strong> to its current
+orientation. This is useful for apps using the camera that want to
+<strong>disable rotation</strong> while shooting video. </p>
+
+<h4 id="43-quick-responses-intent">Intent for handling Quick Responses</h4>
+
+<p>Android 4.3 introduces a new public Intent that lets any app <strong>handle
+Quick Responses</strong> — text messages sent by the user in response to
+an incoming call, without needing to pick up the call or unlock the device. Your
+app can listen for the intent and send the message to the caller over your
+messaging system. The intent includes the recipient (caller) as well as the
+message itself. </p>
+
+
+<h2 id="43-intl">Support for International Users</h2>
+
+<div style="float:right;margin:22px 0px 0px 24px;width:380px;">
+<img src="{@docRoot}images/jb-rtl-arabic-n4.png" alt="" width="180" style="margin-bottom:0;">
+<img src="{@docRoot}images/jb-rtl-hebrew-n4.png" alt="" width="180" style="margin-bottom:0;padding-left:10px;">
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">More parts of Android 4.3 are optimized for RTL languages.</p>
+</div>
+
+<h4 id="43-rtl">RTL improvements</h4>
+
+<p>Android 4.3 includes RTL performance enhancements and broader RTL support
+across framework UI widgets, including ProgressBar/Spinner and
+ExpandableListView. More debugging information visible through the
+<code>uiautomatorviewer</code> tool. In addition, more system UI components are
+now RTL aware, such as notifications, navigation bar and the Action Bar.</p>
+
+<p>To provide a better systemwide experience in RTL scripts, more default system
+apps now support RTL layouts, including Launcher, Quick Settings, Phone, People,
+SetupWizard, Clock, Downloads, and more.</p>
+
+<h4 id="43-localization">Utilities for localization</h4>
+
+<div style="float:right;margin:16px 12px 0px 32px;width:260px;clear:both;">
+<img src="{@docRoot}images/jb-pseudo-locale-zz.png" alt="" width="260" style="margin-bottom:0;">
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">Pseudo-locales make it easier to test your app's localization.</p>
+</div>
+
+<p>Android 4.3 also includes new utilities and APIs for creating better RTL
+strings and testing your localized UIs. A new <strong>BidiFormatter</strong>
+provides a set of simple APIs for wrapping Unicode strings so that you can
+fine-tune your text rendering in RTL scripts. To let you use this utility more
+broadly in your apps, the BidiFormatter APIs are also now available for earlier
+platform versions through the Support Package in the Android SDK. </p>
+
+<p>To assist you with managing date formatting across locales, Android 4.3
+includes a new <strong>getBestDateTimePattern()</strong> method that automatically
+generates the best possible localized form of a Unicode UTS date for a locale
+that you specify. It’s a convenient way to provide a more localized experience
+for your users. </p>
+
+<p>To help you test your app more easily in other locales, Android 4.3
+introduces <strong>pseudo-locales</strong> as a new developer option.
+Pseudo-locales simulate the language, script, and display characteristics
+associated with a locale or language group. Currently, you can test with a
+pseudo-locale for <strong>Accented English</strong>, which lets you see how your
+UI works with script accents and characters used in a variety of European
+languages. <!--To use the pseudo-locale, enable “Developer options” in Settings
+and then select Accented English from Language and Input settings. --></p>
+
+
+<h2 id="43-accessibility">Accessibility and UI Automation</h2>
+
+<p>Starting in Android 4.3, accessibility services can <strong>observe and
+filter key events</strong>, such as to handle keyboard shortcuts or provide
+navigation parity with gesture-based input. The service receives the events and
+can process them as needed before they are passed to the system or other
+installed apps.</p>
+
+<p>Accessibility services can declare <strong>new capability attributes</strong>
+to describe what their services can do and what platform features they use. For
+example, they can declare the capability to filter key events, retrieve window
+content, enable explore-by-touch, or enable web accessibility features. In some
+cases, services must declare a capability attribute before they can access
+related platform features. The system uses the service’s capability attributes
+to generate an opt-in dialog for users, so they can see and agree to the
+capabilities before launch.</p>
+
+<p>Building on the accessibility framework in Android 4.3, a new <strong>UI
+automation framework</strong> lets tests interact with the device’s UI by
+simulating user actions and introspecting the screen content. Through the UI
+automation framework you can perform basic operations, set rotation of the
+screen, generate input events, take screenshots, and much more. It’s a powerful
+way to automate testing in realistic user scenarios, including actions or
+sequences that span multiple apps.</p>
+
+
+<h2 id="43-enterprise-security">Enterprise and Security</h2>
+
+<h4 id="43-wpa2">Wi-Fi configuration for WPA2-Enterprise networks</h4>
+
+<p>Apps can now configure the <strong>Wi-Fi credentials</strong> they need for
+connections to <strong>WPA2 enterprise access points</strong>. Developers can
+use new APIs to configure Extensible Authentication Protocol (EAP) and
+Encapsulated EAP (Phase 2) credentials for authentication methods used in the
+enterprise. Apps with permission to access and change Wi-Fi can configure
+authentication credentials for a variety of EAP and Phase 2 authentication
+methods. </p>
+
+<h4 id="43-selinux">Android sandbox reinforced with SELinux</h4>
+
+<p>Android now uses <strong>SELinux</strong>, a mandatory access control (MAC)
+system in the Linux kernel to augment the UID based application sandbox.
+This protects the operating system against potential security vulnerabilities.</p>
+
+<h4 id="43-keychain">KeyChain enhancements</h4>
+
+<p>The KeyChain API now provides a method that allows applications to confirm
+that system-wide keys are bound to a <strong>hardware root of trust</strong> for
+the device. This provides a place to create or store private keys that
+<strong>cannot be exported</strong> off the device, even in the event of a root or
+kernel compromise.</p>
+
+<h4 id="43-keystore">Android Keystore Provider</h4>
+
+<p>Android 4.3 introduces a keystore provider and APIs that allow applications
+to create exclusive-use keys. Using the APIs, apps can create or store private
+keys that <strong>cannot be seen or used by other apps</strong>, and can be
+added to the keystore without any user interaction. </p>
+
+<p>The keystore provider provides the same security benefits that the KeyChain
+API provides for system-wide credentials, such as binding credentials to a
+device. Private keys in the keystore cannot be exported off the device.</p>
+
+<h4 id="43-seuid">Restrict Setuid from Android Apps</h4>
+
+<p>The <code>/system</code> partition is now mounted <code>nosuid</code> for
+zygote-spawned processes, preventing Android applications from executing
+<code>setuid</code> programs. This reduces root attack surface and likelihood of
+potential security vulnerabilities.</p>
+
+
+<h2 id="43-tools">New Ways to Analyze Performance</h2>
+
+<div style="float:right;margin:16px 6px 0px 32px;width:390px;">
+<img src="{@docRoot}images/jb-systrace.png" alt="" width="390" style="margin-bottom:0;">
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">Systrace uses a new command syntax and lets you collect more types of profiling data.</p>
+</div>
+
+<h4 id="43-systrace">Enhanced Systrace logging</h4>
+
+<p>Android 4.3 supports an enhanced version of the <strong>Systrace</strong>
+tool that’s easier to use and that gives you access to more types of information
+to profile the performance of your app. You can now collect trace data from
+<strong>hardware modules</strong>, <strong>kernel functions</strong>,
+<strong>Dalvik VM</strong> including garbage collection, <strong>resources
+loading</strong>, and more. </p>
+
+<p>Android 4.3 also includes new Trace APIs that you can use in your apps to mark
+specific sections of code to trace using Systrace <strong>begin/end
+events</strong>. When the marked sections of code execute, the system writes the
+begin/end events to the trace log. There's minimal impact on the performance of
+your app, so timings reported give you an accurate view of what your app is
+doing.</p>
+
+<p>You can visualize app-specific events in a timeline in the Systrace output
+file and analyze the events in the context of other kernel and user space trace
+data. Together with existing Systrace tags, custom app sections can give you new
+ways to understand the performance and behavior of your apps.</p>
+
+<div style="float:right;margin:6px 0px 0px 32px;width:380px;">
+<img src="{@docRoot}images/jb-gpu-profile-clk-n4.png" alt="" width="180" style="margin-bottom:0;">
+<img src="{@docRoot}images/jb-gpu-profile-cal-n4.png" alt="" width="180" style="margin-bottom:0;padding-left:10px;">
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">On-screen GPU profiling in Android 4.3.</p>
+</div>
+
+<h4 id="43-gpu-profiling" >On-screen GPU profiling</h4>
+
+<p>Android 4.3 adds new developer options to help you analyze your app’s
+performance and pinpoint rendering issues on any device or emulator.</p>
+
+<p>In the <strong>Profile GPU rendering</strong> option you can now visualize
+your app’s effective framerate on-screen, while the app is running. You can
+choose to display profiling data as on-screen <strong>bar or line
+graphs</strong>, with colors indicating time spent creating drawing commands
+(blue), issuing the commands (orange), and waiting for the commands to complete
+(yellow). The system updates the on-screen graphs continuously, displaying a
+graph for each visible Activity, including the navigation bar and notification
+bar. </p>
+
+<p>A green line highlights the <strong>60ms threshold</strong> for rendering
+operations, so you can assess the your app’s effective framerate relative
+to a 60 fps goal. If you see operations that cross the green line, you
+can analyze them further using Systrace and other tools.</p>
+
+<p class="caution" style="clear:both">On devices running Android 4.2 and higher,
+developer options are hidden by default. You can reveal them at any time by
+tapping 7 times on <strong>Settings > About phone > Build number</strong>
+on any compatible Android device.</p>
+
+<h4 id="43-strictmode">StrictMode warning for file URIs</h4>
+
+<p>The latest addition to the StrictMode tool is a policy constraint that warns
+when your app exposes a <code>file://</code> URI to the system or another app.
+In some cases the receiving app may not have access to the <code>file://</code>
+URI path, so when sharing files between apps, a <code>content://</code> URI should
+be used (with the appropriate permission). This new policy helps you catch and fix
+such cases. If you’re looking for a convenient way to store and expose files to other
+apps, try using the <code>FileProvider</code> content provider that’s available
+in the <a href="{@docRoot}tools/support-library/index.html">Support Library</a>.</p>
+
+</div><!-- END ANDROID 4.3 -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<!-- BEGIN ANDROID 4.2 -->
<div id="android-42" class="version-section">
@@ -75,7 +645,7 @@
new features for users and developers. This document provides a glimpse of what's new for
developers.
-<p>See the <a href="/about/versions/android-4.2.html">Android 4.2 APIs</a>
+<p>See the <a href="{@docRoot}about/versions/android-4.2.html">Android 4.2 APIs</a>
document for a detailed look at the new developer APIs.</p>
<p>Find out more about the new Jelly Bean features for users at <a
@@ -158,7 +728,7 @@
<div>
<img src="{@docRoot}images/jb-lock-calendar.png" alt="Calendar lock screen widget" width="280" height="543" style="padding-left:1em;margin-bottom:0">
</div>
-<p class="image-caption" style="padding:1.5em">You can extend <strong>app widgets</strong> to run on the lock screen, for instant access to your content.</p>
+<p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">You can extend <strong>app widgets</strong> to run on the lock screen, for instant access to your content.</p>
</div>
<h3 id="42-lockscreen-widgets">Lock screen widgets</h3>
diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
index 4778400..2bc90ab 100644
--- a/docs/html/design/building-blocks/tabs.jd
+++ b/docs/html/design/building-blocks/tabs.jd
@@ -53,7 +53,7 @@
<img src="{@docRoot}design/media/tabs_youtube.png">
<div class="figure-caption">
- Tabs in the YouTube app.
+ Tabs in the Google Play Movies app.
</div>
diff --git a/docs/html/design/media/tabs_youtube.png b/docs/html/design/media/tabs_youtube.png
index 4ea6c1c..a4c1ae5f 100644
--- a/docs/html/design/media/tabs_youtube.png
+++ b/docs/html/design/media/tabs_youtube.png
Binary files differ
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index 6020034..ceb5a4c 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -123,7 +123,7 @@
</div>
</div>
-<h2>Action Buttons</h2>
+<h2 id="ActionButtons">Action Buttons</h2>
<p><em>Action buttons</em> on the action bar surface your app's most important activities. Think about which
buttons will get used most often, and order them accordingly. Depending on available screen real
estate, the system shows your most important actions as action buttons and moves the rest to the
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 4da87b9..6f2215a 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,5 +1,5 @@
page.title=Navigation with Back and Up
-page.tags="navigation","activity","task"
+page.tags="navigation","activity","task","up navigation","back navigation"
@jd:body
<a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index f96e868..7e2337c 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -41,6 +41,20 @@
<li class="item carousel-home">
<div class="col-8">
+ <img
+src="//lh4.ggpht.com/-lfjzgG5Dqrk/UHMThRtpRwI/AAAAAAAABpk/h4d3nsmkgPM/s400/mint.png"
+class="play no-shadow no-transform" />
+ </div>
+ <div class="content-right col-6">
+ <h2>Building Great Apps for Tablets</h2>
+ <p>Tablets are a fast-growing part of the Android installed base and they offer new opportunities for user engagement and monetization. If you are targeting tablets, check out this list of tips and techniques on how to deliver a great app experience for tablet users. </p>
+ <p><a
+href="//android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html" class="button">Read
+more</a></p>
+ </div>
+ </li>
+ <li class="item carousel-home">
+ <div class="col-8">
<img src="{@docRoot}images/google/gps-location.png"
class="play no-shadow no-transform" style="margin:0 0 0 70px;height:230px;width:340px" />
</div>
@@ -90,20 +104,6 @@
href="{@docRoot}google/play-services/maps.html" class="button">Read more</a></p>
</div>
</li>
- <li class="item carousel-home">
- <div class="col-8">
- <img
-src="//lh4.ggpht.com/-lfjzgG5Dqrk/UHMThRtpRwI/AAAAAAAABpk/h4d3nsmkgPM/s400/mint.png"
-class="play no-shadow no-transform" />
- </div>
- <div class="content-right col-6">
- <h2>Building Great Apps for Tablets</h2>
- <p>Tablets are a growing part of the Android installed base and they offer new opportunities for user engagement and monetization. If you are targeting tablets, check out the <strong>Tablet App Quality Checklist</strong> for tips and techniques on how to deliver a great app experience for tablet users. </p>
- <p><a
-href="/distribute/googleplay/quality/tablet.html" class="button">Read
-more</a></p>
- </div>
- </li>
<li class="item carousel-home">
<div class="col-8">
<img
@@ -132,26 +132,26 @@
<div class="feed-frame">
<!-- DEVELOPER NEWS -->
<ul>
+ <li><a href="//android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html">
+ <div class="feed-image" style="background:url('//2.bp.blogspot.com/-HfoO6KNFBKA/UeiyRoELb7I/AAAAAAAAAFs/bHR-5viktU4/s1000/icons.png') no-repeat 0 0;background-size:500px;background-position:center center;"></div>
+ <h4>Making Beautiful Android App Icons</h4>
+ <p>As higher density screens gain popularity, it's important to make sure your launcher icon is crisp and high quality...</p>
+ </a></li>
+ <li><a href="//android-developers.blogspot.com/2013/07/beautiful-design-collection-summer-2013.html">
+ <div class="feed-image" style="background:url('//1.bp.blogspot.com/-k8DZYu0daT4/UdRt1AzstvI/AAAAAAAAAFM/CvEkb2yh-i0/s965/beautifulapps_4.png') no-repeat 0 0"></div>
+ <h4>The Beautiful Design Summer 2013 Collection</h4>
+ <p>See the apps chosen by the Android Design for their masterfully crafted design details...</p>
+ </a></li>
+ <li><a href="//android-developers.blogspot.com/2013/06/google-play-developer-8-step-checkup.html">
+ <div class="feed-image" style="background:url('//4.bp.blogspot.com/-LeK74UYY1eM/UbD8L-2DpFI/AAAAAAAACZA/YMjwndr-ZgM/s400/DoctorDroidV2.png') no-repeat 0 0;background-size:130px;background-position:8px -4px;"></div>
+ <h4>Google Play Developer 8-Step Checkup</h4>
+ <p>Give your Google Play developer account this quick checkup to keep it in good order and help you deliver a more successful product to users...</p>
+ </a></li>
<li><a href="//android-developers.blogspot.com/2013/05/new-ways-to-optimize-your-business-in.html">
<div class="feed-image" style="background:url('//4.bp.blogspot.com/-VmHMT66JjxU/UZZdfPUaJsI/AAAAAAAACQc/kDx5-Ep5YRo/s1600/framed_designed-tablets.png') no-repeat 0 0;background-size:180px"></div>
<h4>New Ways to Optimize Your Business in Google Play</h4>
<p>Many of you have invested in making great tablet experiences for your users, and we want to ensure that that work pays off...</p>
</a></li>
- <li><a href="//android-developers.blogspot.com/2013/05/android-studio-ide-built-for-android.html">
- <div class="feed-image" style="background:url('//1.bp.blogspot.com/-u5dfSsMOMC0/UZO_5DC_W9I/AAAAAAAACM8/YCMn15HPzpE/s320/Studio_table.png') no-repeat 0 0;background-size:180px"></div>
- <h4>Android Studio: An IDE built for Android</h4>
- <p>To develop Android Studio, we cooperated with JetBrains, creators of one of the most advanced Java IDEs available today...</p>
- </a></li>
- <li><a href="//android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html">
- <div class="feed-image" style="background:url('//lh4.ggpht.com/7z4NItEg-X21zvFGAarKonk-VaysBYthJ30u1JjaQ0-5fjyHNawnmoNeG--4FCACog=w124') no-repeat 0 0"></div>
- <h4>Verifying Back-End Calls from Android Apps</h4>
- <p>You can take advantage of the auth APIs in Google Play services to let your back end know which app is calling and for which user....</p>
- </a></li>
- <li><a href="//android-developers.blogspot.com/2012/12/daydream-interactive-screen-savers.html">
- <div class="feed-image" style="background:url('//lh4.ggpht.com/-wVsUOo4xGE0/UNy9mZ1nmMI/AAAAAAAAB4w/f6rhyLn5KbI/s1600/daydream-example.jpg') no-repeat 0 0;background-position:right top;"></div>
- <h4>Daydream: Interactive Screen Savers</h4>
- <p>Daydream is an interactive screen-saver mode introduced in Android 4.2. Learn how to add Daydreams to your apps...</p>
- </a></li>
</ul>
<!-- FEATURED DOCS -->
<ul>
diff --git a/docs/html/google/play/publishing/multiple-apks.jd b/docs/html/google/play/publishing/multiple-apks.jd
index 64ddc10..3c7ed0f 100644
--- a/docs/html/google/play/publishing/multiple-apks.jd
+++ b/docs/html/google/play/publishing/multiple-apks.jd
@@ -47,7 +47,7 @@
<li><a href="{@docRoot}google/play/expansion-files.html">APK Expansion Files</a></li>
<li><a href="{@docRoot}google/play/filters.html">Filters on Google Play</a></li>
<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a></li>
- <li><a href="{@docRoot}tools/extras/support-library.html">Support Library</a></li>
+ <li><a href="{@docRoot}tools/support-library/index.html">Support Library</a></li>
<li><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API Levels</a></li>
</ol>
@@ -628,7 +628,7 @@
href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple Screens</a>.</p>
<p>Additionally, you should consider using a support library from the <a
-href="{@docRoot}tools/extras/support-library.html">Compatibility Package</a> so that you can add <a
+href="{@docRoot}tools/support-library/index.html">Compatibility Package</a> so that you can add <a
href="{@docRoot}guide/components/fragments.html">Fragments</a> to your activity designs
when running on larger screens such as tablets.</p>
@@ -643,7 +643,7 @@
href="{@docRoot}about/dashboards/index.html">Platform Versions</a> dashboard).</p>
<p>By using a support library from the <a
-href="{@docRoot}tools/extras/support-library.html">Compatibility Package</a>, you can also use APIs
+href="{@docRoot}tools/support-library/index.html">Compatibility Package</a>, you can also use APIs
from some of the latest versions (such as Android 3.0) while
still supporting versions as low as Android 1.6. The support library includes APIs for <a
href="{@docRoot}guide/components/fragments.html">Fragments</a>, <a
diff --git a/docs/html/guide/components/tasks-and-back-stack.jd b/docs/html/guide/components/tasks-and-back-stack.jd
index a21bf34..f818873 100644
--- a/docs/html/guide/components/tasks-and-back-stack.jd
+++ b/docs/html/guide/components/tasks-and-back-stack.jd
@@ -142,9 +142,8 @@
foreground—all three activities in its stack are intact and the activity at the top of the
stack resumes. At
this point, the user can also switch back to Task B by going Home and selecting the application icon
-that started that task (or by touching and holding the <em>Home</em> button to reveal recent tasks
-and selecting
-one). This is an example of multitasking on Android.</p>
+that started that task (or by selecting the app's task from the <em>recent apps</em> screen).
+This is an example of multitasking on Android.</p>
<p class="note"><strong>Note:</strong> Multiple tasks can be held in the background at once.
However, if the user is running many background tasks at the same time, the system might begin
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 6d95338..db08c3e 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -312,7 +312,7 @@
<span class="en">Canvas and Drawables</span>
</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/graphics/opengl.html">
- <span class="en">OpenGL</span>
+ <span class="en">OpenGL ES</span>
</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/graphics/hardware-accel.html">
<span class="en">Hardware Acceleration</span>
diff --git a/docs/html/guide/practices/optimizing-for-3.0.jd b/docs/html/guide/practices/optimizing-for-3.0.jd
index 465a847..fea54af 100644
--- a/docs/html/guide/practices/optimizing-for-3.0.jd
+++ b/docs/html/guide/practices/optimizing-for-3.0.jd
@@ -54,7 +54,7 @@
<li><a href="tablets-and-handsets.html">Supporting Tablets
and Handsets</a></li>
<li><a
-href="{@docRoot}tools/extras/support-library.html">Compatibility Library</a></li>
+href="{@docRoot}tools/support-library/index.html">Compatibility Library</a></li>
<li><a href="http://code.google.com/p/iosched/">Google I/O App source code</a></li>
</ol>
@@ -281,7 +281,7 @@
to help you add features from Android 3.0 without requiring you to change your <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
or build target, we're providing a static library called the <a
-href="{@docRoot}tools/extras/support-library.html">Compatibility Library</a>
+href="{@docRoot}tools/support-library/index.html">Compatibility Library</a>
(downloadable from the Android SDK Manager).</p>
<p>This library includes APIs for <a
href="{@docRoot}guide/components/fragments.html">fragments</a>, <a
@@ -289,7 +289,7 @@
simply adding this library to your Android project, you can use these APIs in your application and
remain compatible with Android 1.6. For information about how to get the library and start
using it in your application, see the <a
-href="{@docRoot}tools/extras/support-library.html">Compatibility Library</a> document.</p>
+href="{@docRoot}tools/support-library/index.html">Compatibility Library</a> document.</p>
</div>
</div>
diff --git a/docs/html/guide/practices/tablets-and-handsets.jd b/docs/html/guide/practices/tablets-and-handsets.jd
index 8d6d3dd37..a63a368 100644
--- a/docs/html/guide/practices/tablets-and-handsets.jd
+++ b/docs/html/guide/practices/tablets-and-handsets.jd
@@ -141,7 +141,7 @@
<h3>Remaining backward-compatible</h3>
<p>If you want to use fragments in your application <em>and</em> remain compatible with
versions of Android older than 3.0, you can do so by using the Android <a
-href="{@docRoot}tools/extras/support-library.html">Support Library</a> (downloadable from the
+href="{@docRoot}tools/support-library/index.html">Support Library</a> (downloadable from the
SDK Manager).</p>
<p>The support library includes APIs for <a
href="{@docRoot}guide/components/fragments.html">fragments</a>, <a
@@ -150,7 +150,7 @@
backward-compatible versions of these APIs in your application and remain compatible with Android
1.6 (your <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
android:minSdkVersion}</a> value can be as low as {@code "4"}). For information about how to get the
-library and start using it, see the <a href="{@docRoot}tools/extras/support-library.html">Support
+library and start using it, see the <a href="{@docRoot}tools/support-library/index.html">Support
Library</a> document.</p>
<p>The support library <em>does not</em> provide APIs for the action bar, but you can use
diff --git a/docs/html/guide/topics/graphics/opengl.jd b/docs/html/guide/topics/graphics/opengl.jd
index 469eae2..f46113d 100644
--- a/docs/html/guide/topics/graphics/opengl.jd
+++ b/docs/html/guide/topics/graphics/opengl.jd
@@ -1,4 +1,4 @@
-page.title=OpenGL
+page.title=OpenGL ES
page.tags="games"
@jd:body
@@ -9,21 +9,21 @@
<ol>
<li><a href="#basics">The Basics</a>
<ol>
- <li><a href="#packages">OpenGL packages</a></li>
+ <li><a href="#packages">OpenGL ES packages</a></li>
</ol>
<li><a href="#manifest">Declaring OpenGL Requirements</a></li>
- </li>
<li><a href="#coordinate-mapping">Mapping Coordinates for Drawn Objects</a>
<ol>
<li><a href="#proj-es1">Projection and camera in ES 1.0</a></li>
- <li><a href="#proj-es1">Projection and camera in ES 2.0</a></li>
+ <li><a href="#proj-es2">Projection and camera in ES 2.0 and higher</a></li>
</ol>
</li>
- <li><a href="#faces-winding">Shape Faces and Winding</li>
+ <li><a href="#faces-winding">Shape Faces and Winding</a></li>
<li><a href="#compatibility">OpenGL Versions and Device Compatibility</a>
<ol>
<li><a href="#textures">Texture compression support</a></li>
- <li><a href="#gl-extension-query">Determining OpenGL Extensions</a></li>
+ <li><a href="#gl-extension-query">Determining OpenGL extensions</a></li>
+ <li><a href="#version-check">Checking OpenGL ES Version</a></li>
</ol>
</li>
<li><a href="#choosing-version">Choosing an OpenGL API Version</a></li>
@@ -48,20 +48,37 @@
<li><a href="http://www.khronos.org/opengles/">OpenGL ES</a></li>
<li><a href="http://www.khronos.org/opengles/1_X/">OpenGL ES 1.x Specification</a></li>
<li><a href="http://www.khronos.org/opengles/2_X/">OpenGL ES 2.x specification</a></li>
+ <li><a href="http://www.khronos.org/opengles/3_X/">OpenGL ES 3.x specification</a></li>
</ol>
</div>
</div>
<p>Android includes support for high performance 2D and 3D graphics with the Open Graphics Library
-(OpenGL), specifically, the OpenGL ES API. OpenGL is a cross-platform graphics API that specifies a
+(OpenGL®), specifically, the OpenGL ES API. OpenGL is a cross-platform graphics API that specifies a
standard software interface for 3D graphics processing hardware. OpenGL ES is a flavor of the OpenGL
-specification intended for embedded devices. The OpenGL ES 1.0 and 1.1 API specifications have been
-supported since Android 1.0. Beginning with Android 2.2 (API Level 8), the framework supports the
-OpenGL ES 2.0 API specification.</p>
+specification intended for embedded devices. Android supports several versions of the OpenGL ES
+API:</p>
-<p class="note"><b>Note:</b> The specific API provided by the Android framework is similar to the
- J2ME JSR239 OpenGL ES API, but is not identical. If you are familiar with J2ME JSR239
- specification, be alert for variations.</p>
+<ul>
+ <li>OpenGL ES 1.0 and 1.1 - This API specification is supported by Android 1.0 and higher.</li>
+ <li>OpenGL ES 2.0 - This API specification is supported by Android 2.2 (API level 8) and higher.
+ </li>
+ <li>OpenGL ES 3.0 - This API specification is supported by Android 4.3 (API level 18) and higher.
+ </li>
+</ul>
+
+<p class="caution"><strong>Caution:</strong>
+ Support of the OpenGL ES 3.0 API on a device requires an implementation of this graphics
+ pipeline provided by the device manufacturer. A device running Android 4.3 or higher <em>may
+ not support</em> the OpenGL ES 3.0 API. For information on checking what version of OpenGL ES
+ is supported at run time, see <a href="#version-check">Checking OpenGL ES Version</a>.
+</p>
+
+<p class="note"><strong>Note:</strong>
+ The specific API provided by the Android framework is similar to the J2ME JSR239 OpenGL ES API,
+ but is not identical. If you are familiar with J2ME JSR239 specification, be alert for
+ variations.</p>
+
<h2 id="basics">The Basics</h2>
@@ -87,7 +104,7 @@
<a href="{@docRoot}training/graphics/opengl/touch.html">Responding to Touch Events</a>.</dd>
<dt><strong>{@link android.opengl.GLSurfaceView.Renderer}</strong></dt>
- <dd>This interface defines the methods required for drawing graphics in an OpenGL {@link
+ <dd>This interface defines the methods required for drawing graphics in a {@link
android.opengl.GLSurfaceView}. You must provide an implementation of this interface as a
separate class and attach it to your {@link android.opengl.GLSurfaceView} instance using
{@link android.opengl.GLSurfaceView#setRenderer(android.opengl.GLSurfaceView.Renderer)
@@ -123,51 +140,59 @@
</dd>
</dl>
-<h3 id="packages">OpenGL packages</h3>
-<p>Once you have established a container view for OpenGL using {@link
+<h3 id="packages">OpenGL ES packages</h3>
+<p>Once you have established a container view for OpenGL ES using {@link
android.opengl.GLSurfaceView} and {@link android.opengl.GLSurfaceView.Renderer}, you can begin
calling OpenGL APIs using the following classes:</p>
<ul>
<li>OpenGL ES 1.0/1.1 API Packages
<ul>
- <li>{@link android.opengl} - This package provides a static interface to the OpenGL ES
-1.0/1.1 classes and better performance than the javax.microedition.khronos package interfaces.
- <ul>
- <li>{@link android.opengl.GLES10}</li>
- <li>{@link android.opengl.GLES10Ext}</li>
- <li>{@link android.opengl.GLES11}</li>
- <li>{@link android.opengl.GLES11Ext}</li>
- </ul>
- </li>
+ <li>{@link android.opengl} - This package provides a static interface to the OpenGL ES
+ 1.0/1.1 classes and better performance than the {@code javax.microedition.khronos} package
+ interfaces.
+ <ul>
+ <li>{@link android.opengl.GLES10}</li>
+ <li>{@link android.opengl.GLES10Ext}</li>
+ <li>{@link android.opengl.GLES11}</li>
+ <li>{@link android.opengl.GLES11Ext}</li>
+ </ul>
+ </li>
<li>{@link javax.microedition.khronos.opengles} - This package provides the standard
-implementation of OpenGL ES 1.0/1.1.
- <ul>
- <li>{@link javax.microedition.khronos.opengles.GL10}</li>
- <li>{@link javax.microedition.khronos.opengles.GL10Ext}</li>
- <li>{@link javax.microedition.khronos.opengles.GL11}</li>
- <li>{@link javax.microedition.khronos.opengles.GL11Ext}</li>
- <li>{@link javax.microedition.khronos.opengles.GL11ExtensionPack}</li>
- </ul>
+ implementation of OpenGL ES 1.0/1.1.
+ <ul>
+ <li>{@link javax.microedition.khronos.opengles.GL10}</li>
+ <li>{@link javax.microedition.khronos.opengles.GL10Ext}</li>
+ <li>{@link javax.microedition.khronos.opengles.GL11}</li>
+ <li>{@link javax.microedition.khronos.opengles.GL11Ext}</li>
+ <li>{@link javax.microedition.khronos.opengles.GL11ExtensionPack}</li>
+ </ul>
</li>
</ul>
</li>
<li>OpenGL ES 2.0 API Class
<ul>
<li>{@link android.opengl.GLES20 android.opengl.GLES20} - This package provides the
-interface to OpenGL ES 2.0 and is available starting with Android 2.2 (API Level 8).</li>
+ interface to OpenGL ES 2.0 and is available starting with Android 2.2 (API level 8).</li>
+ </ul>
+ </li>
+ <li>OpenGL ES 3.0 API Class
+ <ul>
+ <li>{@link android.opengl.GLES30 android.opengl.GLES30} - This package provides the
+ interface to OpenGL ES 3.0 and is available starting with Android 4.3 (API level 18).</li>
</ul>
</li>
</ul>
-<p>If you'd like to start building an app with OpenGL right away, follow the
-<a href="{@docRoot}training/graphics/opengl/index.html">Displaying Graphics with OpenGL ES</a> class.
+<p>If you want to start building an app with OpenGL ES right away, follow the
+<a href="{@docRoot}training/graphics/opengl/index.html">Displaying Graphics with OpenGL ES</a>
+class.
</p>
<h2 id="manifest">Declaring OpenGL Requirements</h2>
<p>If your application uses OpenGL features that are not available on all devices, you must include
these requirements in your <a
-href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a></code> file.
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a> file.
Here are the most common OpenGL manifest declarations:</p>
<ul>
@@ -176,12 +201,28 @@
shown below.
<pre>
- <!-- Tell the system this app requires OpenGL ES 2.0. -->
- <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+<!-- Tell the system this app requires OpenGL ES 2.0. -->
+<uses-feature android:glEsVersion="0x00020000" android:required="true" />
</pre>
- <p>Adding this declaration causes Google Play to restrict your application from being
- installed on devices that do not support OpenGL ES 2.0.</p>
+ <p>Adding this declaration causes Google Play to restrict your application from being
+ installed on devices that do not support OpenGL ES 2.0. If your application is exclusively for
+ devices that support OpenGL ES 3.0, you can also specify this in your manifest:</p>
+
+<pre>
+<!-- Tell the system this app requires OpenGL ES 3.0. -->
+<uses-feature android:glEsVersion="0x00030000" android:required="true" />
+</pre>
+
+ <p class="note"><strong>Note:</strong>
+ The OpenGL ES 3.0 API is backwards-compatible with the 2.0 API, which means you can be more
+ flexible with your implementation of OpenGL ES in your application. By declaring the OpenGL
+ ES 2.0 API as a requirement in your manifest, you can use that API version as a default, check
+ for the availability of the 3.0 API at run time and then use OpenGL ES 3.0 features if the
+ device supports it. For more information about checking the OpenGL ES version supported by a
+ device, see <a href="#version-check">Checking OpenGL ES Version</a>.
+ </p>
+
</li>
<li><strong>Texture compression requirements</strong> - If your application uses texture
compression formats, you must declare the formats your application supports in your manifest file
@@ -221,6 +262,7 @@
coordinates of your graphics so that they map correctly to Android device screens. The camera view
matrix creates a transformation that renders objects from a specific eye position.</p>
+
<h3 id="proj-es1">Projection and camera view in OpenGL ES 1.0</h3>
<p>In the ES 1.0 API, you apply projection and camera view by creating each matrix and then
adding them to the OpenGL environment.</p>
@@ -235,15 +277,15 @@
OpenGL rendering environment.
<pre>
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- gl.glViewport(0, 0, width, height);
+public void onSurfaceChanged(GL10 gl, int width, int height) {
+ gl.glViewport(0, 0, width, height);
- // make adjustments for screen ratio
- float ratio = (float) width / height;
- gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode
- gl.glLoadIdentity(); // reset the matrix to its default state
- gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection matrix
- }
+ // make adjustments for screen ratio
+ float ratio = (float) width / height;
+ gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode
+ gl.glLoadIdentity(); // reset the matrix to its default state
+ gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection matrix
+}
</pre>
</li>
@@ -258,24 +300,25 @@
which simulates a camera position.
<pre>
- public void onDrawFrame(GL10 gl) {
- ...
- // Set GL_MODELVIEW transformation mode
- gl.glMatrixMode(GL10.GL_MODELVIEW);
- gl.glLoadIdentity(); // reset the matrix to its default state
+public void onDrawFrame(GL10 gl) {
+ ...
+ // Set GL_MODELVIEW transformation mode
+ gl.glMatrixMode(GL10.GL_MODELVIEW);
+ gl.glLoadIdentity(); // reset the matrix to its default state
- // When using GL_MODELVIEW, you must set the camera view
- GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
- ...
- }
+ // When using GL_MODELVIEW, you must set the camera view
+ GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+ ...
+}
</pre>
</li>
</ol>
-<h3 id="proj-es2">Projection and camera view in OpenGL ES 2.0</h3>
-<p>In the ES 2.0 API, you apply projection and camera view by first adding a matrix member to
-the vertex shaders of your graphics objects. With this matrix member added, you can then
+<h3 id="proj-es2">Projection and camera view in OpenGL ES 2.0 and higher</h3>
+
+<p>In the ES 2.0 and 3.0 APIs, you apply projection and camera view by first adding a matrix member
+to the vertex shaders of your graphics objects. With this matrix member added, you can then
generate and apply projection and camera viewing matrices to your objects.</p>
<ol>
@@ -285,20 +328,20 @@
matrices to the coordinates of objects that use this shader.
<pre>
- private final String vertexShaderCode =
+private final String vertexShaderCode =
- // This matrix member variable provides a hook to manipulate
- // the coordinates of objects that use this vertex shader.
- "uniform mat4 uMVPMatrix; \n" +
+ // This matrix member variable provides a hook to manipulate
+ // the coordinates of objects that use this vertex shader.
+ "uniform mat4 uMVPMatrix; \n" +
- "attribute vec4 vPosition; \n" +
- "void main(){ \n" +
- // The matrix must be included as part of gl_Position
- // Note that the uMVPMatrix factor *must be first* in order
- // for the matrix multiplication product to be correct.
- " gl_Position = uMVPMatrix * vPosition; \n" +
+ "attribute vec4 vPosition; \n" +
+ "void main(){ \n" +
+ // The matrix must be included as part of gl_Position
+ // Note that the uMVPMatrix factor *must be first* in order
+ // for the matrix multiplication product to be correct.
+ " gl_Position = uMVPMatrix * vPosition; \n" +
- "} \n";
+ "} \n";
</pre>
<p class="note"><strong>Note:</strong> The example above defines a single transformation matrix
member in the vertex shader into which you apply a combined projection matrix and camera view
@@ -315,38 +358,35 @@
variable defined in the vertex shader above.
<pre>
- public void onSurfaceCreated(GL10 unused, EGLConfig config) {
- ...
- muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
- ...
- }
+public void onSurfaceCreated(GL10 unused, EGLConfig config) {
+ ...
+ muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
+ ...
+}
</pre>
</li>
<li><strong>Create projection and camera viewing matrices</strong> - Generate the projection and
viewing matrices to be applied the graphic objects. The following example code shows how to modify
-the {@link
-android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(javax.microedition.khronos.opengles.GL10,
-javax.microedition.khronos.egl.EGLConfig) onSurfaceCreated()} and {@link
-android.opengl.GLSurfaceView.Renderer#onSurfaceChanged(javax.microedition.khronos.opengles.GL10,
-int, int) onSurfaceChanged()} methods of a {@link android.opengl.GLSurfaceView.Renderer}
-implementation to create camera view matrix and a projection matrix based on the screen aspect ratio
-of the device.
+the {@link android.opengl.GLSurfaceView.Renderer#onSurfaceCreated onSurfaceCreated()} and
+{@link android.opengl.GLSurfaceView.Renderer#onSurfaceChanged onSurfaceChanged()} methods of a
+{@link android.opengl.GLSurfaceView.Renderer} implementation to create camera view matrix and a
+projection matrix based on the screen aspect ratio of the device.
<pre>
- public void onSurfaceCreated(GL10 unused, EGLConfig config) {
- ...
- // Create a camera view matrix
- Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
- }
+public void onSurfaceCreated(GL10 unused, EGLConfig config) {
+ ...
+ // Create a camera view matrix
+ Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+}
- public void onSurfaceChanged(GL10 unused, int width, int height) {
- GLES20.glViewport(0, 0, width, height);
+public void onSurfaceChanged(GL10 unused, int width, int height) {
+ GLES20.glViewport(0, 0, width, height);
- float ratio = (float) width / height;
+ float ratio = (float) width / height;
- // create a projection matrix from device screen geometry
- Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
- }
+ // create a projection matrix from device screen geometry
+ Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
+}
</pre>
</li>
@@ -359,23 +399,24 @@
objects to be rendered by OpenGL.
<pre>
- public void onDrawFrame(GL10 unused) {
- ...
- // Combine the projection and camera view matrices
- Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
+public void onDrawFrame(GL10 unused) {
+ ...
+ // Combine the projection and camera view matrices
+ Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
- // Apply the combined projection and camera view transformations
- GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
+ // Apply the combined projection and camera view transformations
+ GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
- // Draw objects
- ...
- }
+ // Draw objects
+ ...
+}
</pre>
</li>
</ol>
<p>For a complete example of how to apply projection and camera view with OpenGL ES 2.0, see the <a
href="{@docRoot}training/graphics/opengl/index.html">Displaying Graphics with OpenGL ES</a> class.</p>
+
<h2 id="faces-winding">Shape Faces and Winding</h2>
<p>In OpenGL, the face of a shape is a surface defined by three or more points in three-dimensional
@@ -414,35 +455,55 @@
clockwise face as the front face, but doing so requires more code and is likely to confuse
experienced OpenGL developers when you ask them for help. So don’t do that.</p>
+
<h2 id="compatibility">OpenGL Versions and Device Compatibility</h2>
<p>The OpenGL ES 1.0 and 1.1 API specifications have been supported since Android 1.0.
-Beginning with Android 2.2 (API Level 8), the framework supports the OpenGL ES 2.0 API
+Beginning with Android 2.2 (API level 8), the framework supports the OpenGL ES 2.0 API
specification. OpenGL ES 2.0 is supported by most Android devices and is recommended for new
-applications being developed with OpenGL. For information about the relative number of
-Android-powered devices that support a given version of OpenGL ES, see the <a
-href="{@docRoot}resources/dashboard/opengl.html">OpenGL ES Versions Dashboard</a>.</p>
+applications being developed with OpenGL. OpenGL ES 3.0 is supported with Android 4.3
+(API level 18) and higher, on devices that provide an implementation of the OpenGL ES 3.0 API.
+For information about the relative number of Android-powered devices
+that support a given version of OpenGL ES, see the
+<a href="{@docRoot}about/dashboards/index.html#OpenGL">OpenGL ES Version Dashboard</a>.</p>
+
+<p>Graphics programming with OpenGL ES 1.0/1.1 API is significantly different than using the 2.0
+and higher versions. The 1.x version of the API has more convenience methods and a fixed graphics
+pipeline, while the OpenGL ES 2.0 and 3.0 APIs provide more direct control of the pipeline through
+use of OpenGL shaders. You should carefully consider the graphics requirements and choose the API
+version that works best for your application. For more information, see
+<a href="#choosing-version">Choosing an OpenGL API Version</a>.</p>
+
+<p>The OpenGL ES 3.0 API provides additional features and better performance than the 2.0 API and is
+also backward compatible. This means that you can potentially write your application targeting
+OpenGL ES 2.0 and conditionally include OpenGL ES 3.0 graphics features if they are available. For
+more information on checking for availability of the 3.0 API, see
+<a href="#version-check">Checking OpenGL ES Version</a></p>
<h3 id="textures">Texture compression support</h3>
+
<p>Texture compression can significantly increase the performance of your OpenGL application by
reducing memory requirements and making more efficient use of memory bandwidth. The Android
framework provides support for the ETC1 compression format as a standard feature, including a {@link
android.opengl.ETC1Util} utility class and the {@code etc1tool} compression tool (located in the
Android SDK at {@code <sdk>/tools/}). For an example of an Android application that uses
-texture compression, see the <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/CompressedTextureActivity.html"
->CompressedTextureActivity</a> code sample.</p>
+texture compression, see the {@code CompressedTextureActivity} code sample in Android SDK
+({@code <sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/}).</p>
-<p>The ETC format is supported by most Android devices, but it not guarranteed to be available. To
-check if the ETC1 format is supported on a device, call the {@link
-android.opengl.ETC1Util#isETC1Supported() ETC1Util.isETC1Supported()} method.</p>
+<p class="caution"><strong>Caution:</strong> The ETC1 format is supported by most Android devices,
+but it not guaranteed to be available. To check if the ETC1 format is supported on a device, call
+the {@link android.opengl.ETC1Util#isETC1Supported() ETC1Util.isETC1Supported()} method.</p>
<p class="note"><b>Note:</b> The ETC1 texture compression format does not support textures with an
-alpha channel. If your application requires textures with an alpha channel, you should
+transparency (alpha channel). If your application requires textures with transparency, you should
investigate other texture compression formats available on your target devices.</p>
-<p>Beyond the ETC1 format, Android devices have varied support for texture compression based on
+<p>The ETC2/EAC texture compression formats are guaranteed to be available when using the OpenGL ES
+3.0 API. This texture format offers excellent compression ratios with high visual quality and the
+format also supports transparency (alpha channel).</p>
+
+<p>Beyond the ETC formats, Android devices have varied support for texture compression based on
their GPU chipsets and OpenGL implementations. You should investigate texture compression support on
the devices you are are targeting to determine what compression types your application should
support. In order to determine what texture formats are supported on a given device, you must <a
@@ -479,11 +540,12 @@
</ul>
</li>
<li><strong>3DC</strong> - 3DC texture compression (3DC) is a less widely available format that
-supports RGB textures with an an alpha channel. This format is represented by the following OpenGL
-extension name:</li>
+supports RGB textures with an alpha channel. This format is represented by the following OpenGL
+extension name:
<ul>
<li>{@code GL_AMD_compressed_3DC_texture}</li>
</ul>
+ </li>
</ul>
<p class="warning"><strong>Warning:</strong> These texture compression formats are <em>not
@@ -500,6 +562,7 @@
<a
href="{@docRoot}guide/topics/graphics/opengl.html#manifest">OpenGL manifest declarations</a>.</p>
+
<h3 id="gl-extension-query">Determining OpenGL extensions</h3>
<p>Implementations of OpenGL vary by Android device in terms of the extensions to the OpenGL ES API
that are supported. These extensions include texture compressions, but typically also include other
@@ -511,9 +574,10 @@
<li>Run the following code on your target devices to determine what texture compression
formats are supported:
<pre>
- String extensions = javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
+String extensions = javax.microedition.khronos.opengles.GL10.glGetString(
+ GL10.GL_EXTENSIONS);
</pre>
- <p class="warning"><b>Warning:</b> The results of this call <em>vary by device!</em> You
+ <p class="warning"><b>Warning:</b> The results of this call <em>vary by device model!</em> You
must run this call on several target devices to determine what compression types are commonly
supported.</p>
</li>
@@ -522,31 +586,105 @@
</ol>
+<h3 id="version-check">Checking OpenGL ES Version</h3>
+
+<p>There are several versions of the OpenGL ES available on Android devices. You can specify the
+minimum version of the API your application requires in your <a href="#manifest">manifest</a>, but
+you may also want to take advantage of features in a newer API at the same time. For example,
+the OpenGL ES 3.0 API is backward-compatible with the 2.0 version of the API, so you may want to
+write your application so that it uses OpenGL ES 3.0 features, but falls back to the 2.0 API if the
+3.0 API is not available.</p>
+
+<p>Before using OpenGL ES features from a version higher than the minimum required in your
+application manifest, your application should check the version of the API available on the device.
+You can do this in one of two ways:</p>
+
+<ol>
+ <li>Attempt create the higher-level OpenGL ES context ({@link android.opengl.EGLContext}) and
+ check the result.</li>
+ <li>Create a minimum-supported OpenGL ES context and check the version value.</li>
+</ol>
+
+<p>The following example code demonstrates how to check the available OpenGL ES version by creating
+an {@link android.opengl.EGLContext} and checking the result. This example shows how to check for
+OpenGL ES 3.0 version:</p>
+
+<pre>
+private static double glVersion = 3.0;
+
+private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+
+ public EGLContext createContext(
+ EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+
+ Log.w(TAG, "creating OpenGL ES " + glVersion + " context");
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion,
+ EGL10.EGL_NONE };
+ // attempt to create a OpenGL ES 3.0 context
+ EGLContext context = egl.eglCreateContext(
+ display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ return context; // returns null if 3.0 is not supported;
+ }
+}
+</pre>
+
+<p>If the {@code createContext()} method show above returns null, your code should create a OpenGL
+ES 2.0 context instead and fall back to using only that API.</p>
+
+<p>The following code example demonstrates how to check the OpenGL ES version by creating a minimum
+supported context first, and then checking the version string:</p>
+
+<pre>
+// Create a minimum supported OpenGL ES context, then check:
+String version = javax.microedition.khronos.opengles.GL10.glGetString(
+ GL10.GL_VERSION);
+Log.w(TAG, "Version: " + version );
+// The version format is displayed as: "OpenGL ES <major>.<minor>"
+// followed by optional content provided by the implementation.
+</pre>
+
+<p>With this approach, if you discover that the device supports a higher-level API version, you
+must destroy the minimum OpenGL ES context and create a new context with the higher
+available API version.</p>
+
+
<h2 id="choosing-version">Choosing an OpenGL API Version</h2>
-<p>OpenGL ES API version 1.0 (and the 1.1 extensions) and version 2.0 both provide high
+<p>OpenGL ES 1.0 API version (and the 1.1 extensions), version 2.0, and version 3.0 all provide high
performance graphics interfaces for creating 3D games, visualizations and user interfaces. Graphics
-programming for the OpenGL ES 1.0/1.1 API versus ES 2.0 differs significantly, and so developers
-should carefully consider the following factors before starting development with either API:</p>
+progamming for OpenGL ES 2.0 and 3.0 is largely similar, with version 3.0 representing a superset
+of the 2.0 API with additional features. Programming for the OpenGL ES 1.0/1.1 API versus OpenGL ES
+2.0 and 3.0 differs significantly, and so developers should carefully consider the following
+factors before starting development with these APIs:</p>
<ul>
- <li><strong>Performance</strong> - In general, OpenGL ES 2.0 provides faster graphics performance
-than the ES 1.0/1.1 APIs. However, the performance difference can vary depending on the Android
-device your OpenGL application is running on, due to differences in the implementation of the OpenGL
-graphics pipeline.</li>
+ <li><strong>Performance</strong> - In general, OpenGL ES 2.0 and 3.0 provide faster graphics
+ performance than the ES 1.0/1.1 APIs. However, the performance difference can vary depending on
+ the Android device your OpenGL application is running on, due to differences in hardware
+ manufacturer's implementation of the OpenGL ES graphics pipeline.</li>
<li><strong>Device Compatibility</strong> - Developers should consider the types of devices,
-Android versions and the OpenGL ES versions available to their customers. For more information
-on OpenGL compatibility across devices, see the <a href="#compatibility">OpenGL Versions and Device
-Compatibility</a> section.</li>
+ Android versions and the OpenGL ES versions available to their customers. For more information
+ on OpenGL compatibility across devices, see the <a href="#compatibility">OpenGL Versions and
+ Device Compatibility</a> section.</li>
<li><strong>Coding Convenience</strong> - The OpenGL ES 1.0/1.1 API provides a fixed function
-pipeline and convenience functions which are not available in the ES 2.0 API. Developers who are new
-to OpenGL may find coding for OpenGL ES 1.0/1.1 faster and more convenient.</li>
- <li><strong>Graphics Control</strong> - The OpenGL ES 2.0 API provides a higher degree
-of control by providing a fully programmable pipeline through the use of shaders. With more
-direct control of the graphics processing pipeline, developers can create effects that would be
-very difficult to generate using the 1.0/1.1 API.</li>
+ pipeline and convenience functions which are not available in the OpenGL ES 2.0 or 3.0 APIs.
+ Developers who are new to OpenGL ES may find coding for version 1.0/1.1 faster and more
+ convenient.</li>
+ <li><strong>Graphics Control</strong> - The OpenGL ES 2.0 and 3.0 APIs provide a higher degree
+ of control by providing a fully programmable pipeline through the use of shaders. With more
+ direct control of the graphics processing pipeline, developers can create effects that would be
+ very difficult to generate using the 1.0/1.1 API.</li>
+ <li><strong>Texture Support</strong> - The OpenGL ES 3.0 API has the best support for texture
+ compression because it guarantees availability of the ETC2 compression format, which supports
+ transparency. The 1.x and 2.0 API implementations usually include support for ETC1, however
+ this texture format does not support transparency and so you must typically provide resources
+ in other compression formats supported by the devices you are targeting. For more information,
+ see <a href="#textures">Texture compression support</a>.</li>
</ul>
<p>While performance, compatibility, convenience, control and other factors may influence your
decision, you should pick an OpenGL API version based on what you think provides the best experience
for your users.</p>
+
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index adc795d..8df1fdf 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -54,85 +54,85 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd>
<dt>description:</dt>
-<dd>Declares an activity (an {@link android.app.Activity} subclass) that
-implements part of the application's visual user interface. All activities
-must be represented by {@code <activity>}
-elements in the manifest file. Any that are not declared there will not be seen
+<dd>Declares an activity (an {@link android.app.Activity} subclass) that
+implements part of the application's visual user interface. All activities
+must be represented by {@code <activity>}
+elements in the manifest file. Any that are not declared there will not be seen
by the system and will never be run.
<dt>attributes:</dt>
<dd><dl class="attr">
<dt><a name="reparent"></a>{@code android:allowTaskReparenting}</dt>
-<dd>Whether or not the activity can move from the task that started it to
-the task it has an affinity for when that task is next brought to the
-front — "{@code true}" if it can move, and "{@code false}" if it
-must remain with the task where it started.
+<dd>Whether or not the activity can move from the task that started it to
+the task it has an affinity for when that task is next brought to the
+front — "{@code true}" if it can move, and "{@code false}" if it
+must remain with the task where it started.
<p>
-If this attribute is not set, the value set by the corresponding
+If this attribute is not set, the value set by the corresponding
<code><a href="{@docRoot}guide/topics/manifest/application-element.html#reparent">allowTaskReparenting</a></code>
-attribute of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element
+attribute of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element
applies to the activity. The default value is "{@code false}".
</p>
<p>
-Normally when an activity is started, it's associated with the task of
-the activity that started it and it stays there for its entire lifetime.
-You can use this attribute to force it to be re-parented to the task it
-has an affinity for when its current task is no longer displayed.
-Typically, it's used to cause the activities of an application to move
+Normally when an activity is started, it's associated with the task of
+the activity that started it and it stays there for its entire lifetime.
+You can use this attribute to force it to be re-parented to the task it
+has an affinity for when its current task is no longer displayed.
+Typically, it's used to cause the activities of an application to move
to the main task associated with that application.
</p>
<p>
-For example, if an e-mail message contains a link to a web page, clicking
-the link brings up an activity that can display the page. That activity
-is defined by the browser application, but is launched as part of the e-mail
-task. If it's reparented to the browser task, it will be shown when the
-browser next comes to the front, and will be absent when the e-mail task
+For example, if an e-mail message contains a link to a web page, clicking
+the link brings up an activity that can display the page. That activity
+is defined by the browser application, but is launched as part of the e-mail
+task. If it's reparented to the browser task, it will be shown when the
+browser next comes to the front, and will be absent when the e-mail task
again comes forward.
</p>
<p>
-The affinity of an activity is defined by the
-<code><a href="#aff">taskAffinity</a></code> attribute. The affinity
+The affinity of an activity is defined by the
+<code><a href="#aff">taskAffinity</a></code> attribute. The affinity
of a task is determined by reading the affinity of its root activity.
Therefore, by definition, a root activity is always in a task with the
-same affinity. Since activities with "{@code singleTask}" or
+same affinity. Since activities with "{@code singleTask}" or
"{@code singleInstance}" launch modes can only be at the root of a task,
-re-parenting is limited to the "{@code standard}" and "{@code singleTop}"
-modes. (See also the <code><a href="#lmode">launchMode</a></code>
+re-parenting is limited to the "{@code standard}" and "{@code singleTop}"
+modes. (See also the <code><a href="#lmode">launchMode</a></code>
attribute.)
</p></dd>
<dt><a name="always"></a>{@code android:alwaysRetainTaskState}</dt>
-<dd>Whether or not the state of the task that the activity is in will always
-be maintained by the system — "{@code true}" if it will be, and
-"{@code false}" if the system is allowed to reset the task to its initial
-state in certain situations. The default value is "{@code false}". This
-attribute is meaningful only for the root activity of a task; it's ignored
+<dd>Whether or not the state of the task that the activity is in will always
+be maintained by the system — "{@code true}" if it will be, and
+"{@code false}" if the system is allowed to reset the task to its initial
+state in certain situations. The default value is "{@code false}". This
+attribute is meaningful only for the root activity of a task; it's ignored
for all other activities.
<p>
-Normally, the system clears a task (removes all activities from the stack
-above the root activity) in certain situations when the user re-selects that
-task from the home screen. Typically, this is done if the user hasn't visited
+Normally, the system clears a task (removes all activities from the stack
+above the root activity) in certain situations when the user re-selects that
+task from the home screen. Typically, this is done if the user hasn't visited
the task for a certain amount of time, such as 30 minutes.
</p>
<p>
-However, when this attribute is "{@code true}", users will always return
-to the task in its last state, regardless of how they get there. This is
-useful, for example, in an application like the web browser where there is
+However, when this attribute is "{@code true}", users will always return
+to the task in its last state, regardless of how they get there. This is
+useful, for example, in an application like the web browser where there is
a lot of state (such as multiple open tabs) that users would not like to lose.
</p></dd>
<dt><a name="clear"></a>{@code android:clearTaskOnLaunch}</dt>
-<dd>Whether or not all activities will be removed from the task, except for
-the root activity, whenever it is re-launched from the home screen —
-"{@code true}" if the task is always stripped down to its root activity, and
-"{@code false}" if not. The default value is "{@code false}". This attribute
-is meaningful only for activities that start a new task (the root activity);
+<dd>Whether or not all activities will be removed from the task, except for
+the root activity, whenever it is re-launched from the home screen —
+"{@code true}" if the task is always stripped down to its root activity, and
+"{@code false}" if not. The default value is "{@code false}". This attribute
+is meaningful only for activities that start a new task (the root activity);
it's ignored for all other activities in the task.
<p>
@@ -140,24 +140,24 @@
are brought to its root activity regardless of what they were last doing in
the task and regardless of whether they used the <em>Back</em> or <em>Home</em> button to
leave it. When the value is "{@code false}", the task may be cleared of activities in
-some situations (see the
-<code><a href="#always">alwaysRetainTaskState</a></code> attribute), but not always.
+some situations (see the
+<code><a href="#always">alwaysRetainTaskState</a></code> attribute), but not always.
</p>
<p>
-Suppose, for example, that someone launches activity P from the home screen,
-and from there goes to activity Q. The user next presses <em>Home</em>, and then returns
-to activity P. Normally, the user would see activity Q, since that is what they
-were last doing in P's task. However, if P set this flag to "{@code true}", all
-of the activities on top of it (Q in this case) were removed when the user pressed
-<em>Home</em> and the task went to the background. So the user sees only P when returning
+Suppose, for example, that someone launches activity P from the home screen,
+and from there goes to activity Q. The user next presses <em>Home</em>, and then returns
+to activity P. Normally, the user would see activity Q, since that is what they
+were last doing in P's task. However, if P set this flag to "{@code true}", all
+of the activities on top of it (Q in this case) were removed when the user pressed
+<em>Home</em> and the task went to the background. So the user sees only P when returning
to the task.
</p>
<p>
-If this attribute and <code><a href="#reparent">allowTaskReparenting</a></code>
-are both "{@code true}", any activities that can be re-parented are moved to
-the task they share an affinity with; the remaining activities are then dropped,
+If this attribute and <code><a href="#reparent">allowTaskReparenting</a></code>
+are both "{@code true}", any activities that can be re-parented are moved to
+the task they share an affinity with; the remaining activities are then dropped,
as described above.
</p></dd>
@@ -169,7 +169,7 @@
onConfigurationChanged()}</code> method is called.
<p class="note"><strong>Note:</strong> Using this attribute should be
-avoided and used only as a last-resort. Please read <a
+avoided and used only as a last resort. Please read <a
href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime Changes</a> for more
information about how to properly handle a restart due to a configuration change.</p>
@@ -220,11 +220,11 @@
<td>"{@code uiMode}"</td>
<td>The user interface mode has changed — this can be caused when the user places the
device into a desk/car dock or when the night mode changes. See {@link
-android.app.UiModeManager}.
+android.app.UiModeManager}.
<em>Added in API level 8</em>.</td>
</tr><tr>
<td>"{@code orientation}"</td>
- <td>The screen orientation has changed — the user has rotated the device.
+ <td>The screen orientation has changed — the user has rotated the device.
<p class="note"><strong>Note:</strong> If your application targets API level 13 or higher (as
declared by the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
minSdkVersion}</a> and <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
@@ -258,70 +258,70 @@
</table>
<p>
-All of these configuration changes can impact the resource values seen by the
-application. Therefore, when <code>{@link android.app.Activity#onConfigurationChanged
-onConfigurationChanged()}</code> is called, it will generally be necessary to again
-retrieve all resources (including view layouts, drawables, and so on) to correctly
-handle the change.
+All of these configuration changes can impact the resource values seen by the
+application. Therefore, when <code>{@link android.app.Activity#onConfigurationChanged
+onConfigurationChanged()}</code> is called, it will generally be necessary to again
+retrieve all resources (including view layouts, drawables, and so on) to correctly
+handle the change.
</p></dd>
<dt><a name="enabled"></a>{@code android:enabled}</dt>
-<dd>Whether or not the activity can be instantiated by the system —
-"{@code true}" if it can be, and "{@code false}" if not. The default value
+<dd>Whether or not the activity can be instantiated by the system —
+"{@code true}" if it can be, and "{@code false}" if not. The default value
is "{@code true}".
<p>
-The <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element has its own
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html#enabled">enabled</a></code>
-attribute that applies to all application components, including activities. The
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
-and {@code <activity>} attributes must both be "{@code true}" (as they both
-are by default) for the system to be able to instantiate the activity. If either
+The <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element has its own
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#enabled">enabled</a></code>
+attribute that applies to all application components, including activities. The
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
+and {@code <activity>} attributes must both be "{@code true}" (as they both
+are by default) for the system to be able to instantiate the activity. If either
is "{@code false}", it cannot be instantiated.
</p></dd>
<dt><a name="exclude"></a>{@code android:excludeFromRecents}</dt>
<dd>Whether or not the task initiated by this activity should be excluded from the list of recently
used applications ("recent apps"). That is, when this activity is the root activity of a new task,
-this attribute determines whether the task should not appear in the list of recent apps. "{@code
-true}" if the task should be <em>excluded</em> from the list; "{@code false}" if it should be
+this attribute determines whether the task should not appear in the list of recent apps. Set "{@code
+true}" if the task should be <em>excluded</em> from the list; set "{@code false}" if it should be
<em>included</em>. The default value is "{@code false}".
</p></dd>
<dt><a name="exported"></a>{@code android:exported}</dt>
-<dd>Whether or not the activity can be launched by components of other
-applications — "{@code true}" if it can be, and "{@code false}" if not.
-If "{@code false}", the activity can be launched only by components of the
-same application or applications with the same user ID.
+<dd>Whether or not the activity can be launched by components of other
+applications — "{@code true}" if it can be, and "{@code false}" if not.
+If "{@code false}", the activity can be launched only by components of the
+same application or applications with the same user ID.
<p>
-The default value depends on whether the activity contains intent filters. The
-absence of any filters means that the activity can be invoked only by specifying
-its exact class name. This implies that the activity is intended only for
-application-internal use (since others would not know the class name). So in
+The default value depends on whether the activity contains intent filters. The
+absence of any filters means that the activity can be invoked only by specifying
+its exact class name. This implies that the activity is intended only for
+application-internal use (since others would not know the class name). So in
this case, the default value is "{@code false}".
-On the other hand, the presence of at least one filter implies that the activity
+On the other hand, the presence of at least one filter implies that the activity
is intended for external use, so the default value is "{@code true}".
</p>
<p>
This attribute is not the only way to limit an activity's exposure to other
-applications. You can also use a permission to limit the external entities that
-can invoke the activity (see the
-<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#prmsn">permission</a></code>
+applications. You can also use a permission to limit the external entities that
+can invoke the activity (see the
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#prmsn">permission</a></code>
attribute).
</p></dd>
<dt><a name="finish"></a>{@code android:finishOnTaskLaunch}</dt>
-<dd>Whether or not an existing instance of the activity should be shut down
-(finished) whenever the user again launches its task (chooses the task on the
-home screen) — "{@code true}" if it should be shut down, and "{@code false}"
+<dd>Whether or not an existing instance of the activity should be shut down
+(finished) whenever the user again launches its task (chooses the task on the
+home screen) — "{@code true}" if it should be shut down, and "{@code false}"
if not. The default value is "{@code false}".
<p>
-If this attribute and
-<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
-are both "{@code true}", this attribute trumps the other. The affinity of the
+If this attribute and
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
+are both "{@code true}", this attribute trumps the other. The affinity of the
activity is ignored. The activity is not re-parented, but destroyed.
</p>
@@ -346,58 +346,58 @@
</dd>
<dt><a name="icon"></a>{@code android:icon}</dt>
-<dd>An icon representing the activity. The icon is displayed to users when
-a representation of the activity is required on-screen. For example, icons
-for activities that initiate tasks are displayed in the launcher window.
+<dd>An icon representing the activity. The icon is displayed to users when
+a representation of the activity is required on-screen. For example, icons
+for activities that initiate tasks are displayed in the launcher window.
The icon is often accompanied by a label (see the <a href="#label">{@code
android:label}</a> attribute).
</p>
<p>
-This attribute must be set as a reference to a drawable resource containing
-the image definition. If it is not set, the icon specified for the application
-as a whole is used instead (see the
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
+This attribute must be set as a reference to a drawable resource containing
+the image definition. If it is not set, the icon specified for the application
+as a whole is used instead (see the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
element's <code><a href="{@docRoot}guide/topics/manifest/application-element.html#icon">icon</a></code> attribute).
</p>
<p>
-The activity's icon — whether set here or by the
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
-element — is also the default icon for all the activity's intent filters (see the
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> element's
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#icon">icon</a></code> attribute).
+The activity's icon — whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
+element — is also the default icon for all the activity's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#icon">icon</a></code> attribute).
</p></dd>
<dt><a name="label"></a>{@code android:label}</dt>
-<dd>A user-readable label for the activity. The label is displayed on-screen
-when the activity must be represented to the user. It's often displayed along
+<dd>A user-readable label for the activity. The label is displayed on-screen
+when the activity must be represented to the user. It's often displayed along
with the activity icon.
<p>
-If this attribute is not set, the label set for the application as a whole is
-used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element's
+If this attribute is not set, the label set for the application as a whole is
+used instead (see the <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element's
<code><a href="{@docRoot}guide/topics/manifest/application-element.html#label">label</a></code> attribute).
</p>
<p>
-The activity's label — whether set here or by the
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element — is also the
-default label for all the activity's intent filters (see the
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> element's
-<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#label">label</a></code> attribute).
+The activity's label — whether set here or by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element — is also the
+default label for all the activity's intent filters (see the
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html#label">label</a></code> attribute).
</p>
<p>
The label should be set as a reference to a string resource, so that
-it can be localized like other strings in the user interface.
-However, as a convenience while you're developing the application,
+it can be localized like other strings in the user interface.
+However, as a convenience while you're developing the application,
it can also be set as a raw string.
</p></dd>
<dt><a name="lmode"></a>{@code android:launchMode}</dt>
<dd>An instruction on how the activity should be launched. There are four modes
-that work in conjunction with activity flags ({@code FLAG_ACTIVITY_*} constants)
+that work in conjunction with activity flags ({@code FLAG_ACTIVITY_*} constants)
in {@link android.content.Intent} objects to determine what should happen when
the activity is called upon to handle an intent. They are:</p>
@@ -417,7 +417,7 @@
An activity with the "{@code standard}" or "{@code singleTop}" launch mode
can be instantiated multiple times. The instances can belong to any task
and can be located anywhere in the activity stack. Typically, they're
-launched into the task that called
+launched into the task that called
<code>{@link android.content.Context#startActivity startActivity()}</code>
(unless the Intent object contains a
<code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code>
@@ -433,7 +433,7 @@
</p>
<p>
-The "{@code standard}" and "{@code singleTop}" modes differ from each other
+The "{@code standard}" and "{@code singleTop}" modes differ from each other
in just one respect: Every time there's a new intent for a "{@code standard}"
activity, a new instance of the class is created to respond to that intent.
Each instance handles a single intent.
@@ -509,41 +509,41 @@
— <code>singleTask</code> and <code>singleInstance</code> — are
<span style="color:red">not appropriate for most applications</span>,
since they result in an interaction model that is likely to be unfamiliar to
-users and is very different from most other applications.
+users and is very different from most other applications.
<p>Regardless of the launch mode that you choose, make sure to test the usability
of the activity during launch and when navigating back to it from
other activities and tasks using the <em>Back</em> button. </p>
<p>For more information on launch modes and their interaction with Intent
-flags, see the
+flags, see the
<a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a>
document.
</p>
</dd>
<dt><a name="multi"></a>{@code android:multiprocess}</dt>
-<dd>Whether an instance of the activity can be launched into the process of the component
-that started it — "{@code true}" if it can be, and "{@code false}" if not.
+<dd>Whether an instance of the activity can be launched into the process of the component
+that started it — "{@code true}" if it can be, and "{@code false}" if not.
The default value is "{@code false}".
<p>
-Normally, a new instance of an activity is launched into the process of the
-application that defined it, so all instances of the activity run in the same
-process. However, if this flag is set to "{@code true}", instances of the
-activity can run in multiple processes, allowing the system to create instances
-wherever they are used (provided permissions allow it), something that is almost
+Normally, a new instance of an activity is launched into the process of the
+application that defined it, so all instances of the activity run in the same
+process. However, if this flag is set to "{@code true}", instances of the
+activity can run in multiple processes, allowing the system to create instances
+wherever they are used (provided permissions allow it), something that is almost
never necessary or desirable.
</p></dd>
<dt><a name="nm"></a>{@code android:name}</dt>
-<dd>The name of the class that implements the activity, a subclass of
-{@link android.app.Activity}. The attribute value should be a fully qualified
-class name (such as, "{@code com.example.project.ExtracurricularActivity}").
-However, as a shorthand, if the first character of the name is a period
-(for example, "{@code .ExtracurricularActivity}"), it is appended to the
-package name specified in the
-<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>
+<dd>The name of the class that implements the activity, a subclass of
+{@link android.app.Activity}. The attribute value should be a fully qualified
+class name (such as, "{@code com.example.project.ExtracurricularActivity}").
+However, as a shorthand, if the first character of the name is a period
+(for example, "{@code .ExtracurricularActivity}"), it is appended to the
+package name specified in the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>
element.
<p>Once you publish your application, you <a
href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html">should not
@@ -557,9 +557,9 @@
<!-- ##api level 3## -->
<dt><a name="nohist"></a>{@code android:noHistory}</dt>
<dd>Whether or not the activity should be removed from the activity stack and
-finished (its <code>{@link android.app.Activity#finish finish()}</code>
-method called) when the user navigates away from it and it's no longer
-visible on screen — "{@code true}" if it should be finished, and
+finished (its <code>{@link android.app.Activity#finish finish()}</code>
+method called) when the user navigates away from it and it's no longer
+visible on screen — "{@code true}" if it should be finished, and
"{@code false}" if not. The default value is "{@code false}".
<p>
@@ -575,14 +575,33 @@
<!-- api level 16 -->
<dt><a name="parent"></a>{@code android:parentActivityName}</dt>
-<dd>The class name of the logical parent of the activity. The name here must be formatted
- the same as the corresponding activity is declared in its own
- <a href="#nm">android:name</a>.
-
+<dd>The class name of the logical parent of the activity. The name here must match the class
+ name given to the corresponding {@code <activity>} element's
+ <a href="#nm"><code>android:name</code></a> attribute.
+
<p>The system reads this attribute to determine which activity should be started when
the use presses the Up button in the action bar. The system can also use this information to
synthesize a back stack of activities with {@link android.app.TaskStackBuilder}.</p>
+<p>To support API levels 4 - 16, you can also declare the parent activity with a {@code
+<meta-data>} element that specifies a value for {@code "android.support.PARENT_ACTIVITY"}.
+For example:</p>
+<pre>
+<activity
+ android:name="com.example.app.ChildActivity"
+ android:label="@string/title_child_activity"
+ android:parentActivityName="com.example.myfirstapp.MainActivity" >
+ <!-- Parent activity meta-data to support API level 4+ -->
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="com.example.app.MainActivity" />
+</activity>
+</pre>
+
+<p>For more information about declaring the parent activity to support Up navigation,
+read <a href="{@docRoot}training/implementing-navigation/ancestral.html">Providing Up
+Navigation</a>.</p>
+
<p>
This attribute was introduced in API Level 16.
</p>
@@ -591,63 +610,67 @@
<dt><a name="prmsn"></a>{@code android:permission}</dt>
-<dd>The name of a permission that clients must have to launch the activity
-or otherwise get it to respond to an intent. If a caller of
+<dd>The name of a permission that clients must have to launch the activity
+or otherwise get it to respond to an intent. If a caller of
<code>{@link android.content.Context#startActivity startActivity()}</code> or
<code>{@link android.app.Activity#startActivityForResult startActivityForResult()}</code>
-has not been granted the specified permission, its intent will not be
+has not been granted the specified permission, its intent will not be
delivered to the activity.
<p>
-If this attribute is not set, the permission set by the
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
+If this attribute is not set, the permission set by the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
element's
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html#prmsn">permission</a></code>
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#prmsn">permission</a></code>
attribute applies to the activity. If neither attribute is set, the activity is
not protected by a permission.
</p>
<p>
-For more information on permissions, see the
-<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
-section in the introduction and another document,
+For more information on permissions, see the
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
+section in the introduction and another document,
<a href="{@docRoot}guide/topics/security/security.html">Security and
Permissions</a>.
</p></dd>
<dt><a name="proc"></a>{@code android:process}</dt>
-<dd>The name of the process in which the activity should run. Normally,
-all components of an application run in the default process created for the
-application. It has the same name as the application package. The <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element's
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html#proc">process</a></code>
-attribute can set a different default for all components. But each component
-can override the default, allowing you to spread your application across
+<dd>The name of the process in which the activity should run. Normally, all components of an
+application run in a default process name created for the application and you do
+not need to use this attribute. But if necessary, you can override the default process
+name with this attribute, allowing you to spread your app components across
multiple processes.
<p>
-If the name assigned to this attribute begins with a colon (':'), a new
-process, private to the application, is created when it's needed and
+If the name assigned to this attribute begins with a colon (':'), a new
+process, private to the application, is created when it's needed and
the activity runs in that process.
-If the process name begins with a lowercase character, the activity will run
+If the process name begins with a lowercase character, the activity will run
in a global process of that name, provided that it has permission to do so.
-This allows components in different applications to share a process, reducing
+This allows components in different applications to share a process, reducing
resource usage.
-</p></dd>
+</p>
+
+<p>The <code><a href="{@docRoot}guide/topics/manifest/application-element.html"
+><application></a></code> element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#proc">process</a></code>
+attribute can set a different default process name for all components.
+</dd>
<dt><a name="screen"></a>{@code android:screenOrientation}</dt>
-<dd>The orientation of the activity's display on the device.
-
+<dd>The orientation of the activity's display on the device.
+
<p>The value can be any one of the following strings:</p>
<table>
<tr>
<td>"{@code unspecified}"</td>
<td>The default value. The system chooses the orientation. The policy it
- uses, and therefore the choices made in specific contexts, may differ
+ uses, and therefore the choices made in specific contexts, may differ
from device to device.</td>
</tr><tr>
<td>"{@code behind}"</td>
- <td>The same orientation as the activity that's immediately beneath it in
+ <td>The same orientation as the activity that's immediately beneath it in
the activity stack.</td>
</tr><tr>
<td>"{@code landscape}"</td>
@@ -736,76 +759,76 @@
</dd>
<dt><a name="state"></a>{@code android:stateNotNeeded}</dt>
-<dd>Whether or not the activity can be killed and successfully restarted
-without having saved its state — "{@code true}" if it can be restarted
-without reference to its previous state, and "{@code false}" if its previous
+<dd>Whether or not the activity can be killed and successfully restarted
+without having saved its state — "{@code true}" if it can be restarted
+without reference to its previous state, and "{@code false}" if its previous
state is required. The default value is "{@code false}".
<p>
-Normally, before an activity is temporarily shut down to save resources, its
-<code>{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}</code>
-method is called. This method stores the current state of the activity in a
-{@link android.os.Bundle} object, which is then passed to
-<code>{@link android.app.Activity#onCreate onCreate()}</code> when the activity
-is restarted. If this attribute is set to "{@code true}",
-{@code onSaveInstanceState()} may not be called and {@code onCreate()} will
-be passed {@code null} instead of the Bundle — just as it was when the
+Normally, before an activity is temporarily shut down to save resources, its
+<code>{@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}</code>
+method is called. This method stores the current state of the activity in a
+{@link android.os.Bundle} object, which is then passed to
+<code>{@link android.app.Activity#onCreate onCreate()}</code> when the activity
+is restarted. If this attribute is set to "{@code true}",
+{@code onSaveInstanceState()} may not be called and {@code onCreate()} will
+be passed {@code null} instead of the Bundle — just as it was when the
activity started for the first time.
</p>
<p>
-A "{@code true}" setting ensures that the activity can be restarted in the
-absence of retained state. For example, the activity that displays the
-home screen uses this setting to make sure that it does not get removed if it
+A "{@code true}" setting ensures that the activity can be restarted in the
+absence of retained state. For example, the activity that displays the
+home screen uses this setting to make sure that it does not get removed if it
crashes for some reason.
</p></dd>
<dt><a name="aff"></a>{@code android:taskAffinity}</dt>
-<dd>The task that the activity has an affinity for. Activities with
+<dd>The task that the activity has an affinity for. Activities with
the same affinity conceptually belong to the same task (to the same
-"application" from the user's perspective). The affinity of a task
-is determined by the affinity of its root activity.
+"application" from the user's perspective). The affinity of a task
+is determined by the affinity of its root activity.
<p>
-The affinity determines two things — the task that the activity is re-parented
-to (see the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
-attribute) and the task that will house the activity when it is launched
-with the <code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code>
+The affinity determines two things — the task that the activity is re-parented
+to (see the <code><a href="{@docRoot}guide/topics/manifest/activity-element.html#reparent">allowTaskReparenting</a></code>
+attribute) and the task that will house the activity when it is launched
+with the <code>{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}</code>
flag.
</p>
<p>
By default, all activities in an application have the same affinity. You
can set this attribute to group them differently, and even place
-activities defined in different applications within the same task. To
+activities defined in different applications within the same task. To
specify that the activity does not have an affinity for any task, set
it to an empty string.
<p>
-If this attribute is not set, the activity inherits the affinity set
-for the application (see the
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
-element's
+If this attribute is not set, the activity inherits the affinity set
+for the application (see the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
+element's
<code><a href="{@docRoot}guide/topics/manifest/application-element.html#aff">taskAffinity</a></code>
-attribute). The name of the default affinity for an application is
-the package name set by the
-<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>
+attribute). The name of the default affinity for an application is
+the package name set by the
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>
element.
</p>
<dt><a name="theme"></a>{@code android:theme}</dt>
-<dd>A reference to a style resource defining an overall theme for the activity.
+<dd>A reference to a style resource defining an overall theme for the activity.
This automatically sets the activity's context to use this theme (see
-<code>{@link android.content.Context#setTheme setTheme()}</code>, and may also
-cause "starting" animations prior to the activity being launched (to better
+<code>{@link android.content.Context#setTheme setTheme()}</code>, and may also
+cause "starting" animations prior to the activity being launched (to better
match what the activity actually looks like).
<p>
-If this attribute is not set, the activity inherits the theme set for the
-application as a whole — from the
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
-element's
-<code><a href="{@docRoot}guide/topics/manifest/application-element.html#theme">theme</a></code>
+If this attribute is not set, the activity inherits the theme set for the
+application as a whole — from the
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
+element's
+<code><a href="{@docRoot}guide/topics/manifest/application-element.html#theme">theme</a></code>
attribute. If that attribute is also not set, the default system theme is used. For more
information, see the <a
href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a> developer guide.
@@ -837,32 +860,32 @@
<!-- ##api level 3## -->
<dt><a name="wsoft"></a>{@code android:windowSoftInputMode}</dt>
-<dd>How the main window of the activity interacts with the window containing
-the on-screen soft keyboard. The setting for this attribute affects two
-things:
+<dd>How the main window of the activity interacts with the window containing
+the on-screen soft keyboard. The setting for this attribute affects two
+things:
-<ul>
-<li>The state of the soft keyboard — whether it is hidden or visible
+<ul>
+<li>The state of the soft keyboard — whether it is hidden or visible
— when the activity becomes the focus of user attention.</li>
-<li>The adjustment made to the activity's main window — whether it is
-resized smaller to make room for the soft keyboard or whether its contents
-pan to make the current focus visible when part of the window is covered by
+<li>The adjustment made to the activity's main window — whether it is
+resized smaller to make room for the soft keyboard or whether its contents
+pan to make the current focus visible when part of the window is covered by
the soft keyboard.</li>
</ul>
<p>
-The setting must be one of the values listed in the following table, or a
-combination of one "{@code state...}" value plus one "{@code adjust...}"
-value. Setting multiple values in either group — multiple
-"{@code state...}" values, for example — has undefined results.
+The setting must be one of the values listed in the following table, or a
+combination of one "{@code state...}" value plus one "{@code adjust...}"
+value. Setting multiple values in either group — multiple
+"{@code state...}" values, for example — has undefined results.
Individual values are separated by a vertical bar ({@code |}). For example:
</p>
<pre><activity android:windowSoftInputMode="stateVisible|adjustResize" . . . ></pre>
<p>
-Values set here (other than "{@code stateUnspecified}" and
+Values set here (other than "{@code stateUnspecified}" and
"{@code adjustUnspecified}") override values set in the theme.
</p>
@@ -872,9 +895,9 @@
<th>Description</th>
</tr><tr>
<td>"{@code stateUnspecified}"</td>
- <td>The state of the soft keyboard (whether it is hidden or visible)
+ <td>The state of the soft keyboard (whether it is hidden or visible)
is not specified. The system will choose an appropriate state or
- rely on the setting in the theme.
+ rely on the setting in the theme.
<p>
This is the default setting for the behavior of the soft keyboard.
@@ -885,32 +908,32 @@
whether visible or hidden, when the activity comes to the fore.</td>
</tr></tr>
<td>"{@code stateHidden}"</td>
- <td>The soft keyboard is hidden when the user chooses the activity
- — that is, when the user affirmatively navigates forward to the
+ <td>The soft keyboard is hidden when the user chooses the activity
+ — that is, when the user affirmatively navigates forward to the
activity, rather than backs into it because of leaving another activity.</td>
</tr></tr>
<td>"{@code stateAlwaysHidden}"</td>
- <td>The soft keyboard is always hidden when the activity's main window
+ <td>The soft keyboard is always hidden when the activity's main window
has input focus.</td>
</tr></tr>
<td>"{@code stateVisible}"</td>
- <td>The soft keyboard is visible when that's normally appropriate
+ <td>The soft keyboard is visible when that's normally appropriate
(when the user is navigating forward to the activity's main window).</td>
</tr></tr>
<td>"{@code stateAlwaysVisible}"</td>
- <td>The soft keyboard is made visible when the user chooses the
- activity — that is, when the user affirmatively navigates forward
- to the activity, rather than backs into it because of leaving another
+ <td>The soft keyboard is made visible when the user chooses the
+ activity — that is, when the user affirmatively navigates forward
+ to the activity, rather than backs into it because of leaving another
activity.</td>
</tr></tr>
<td>"{@code adjustUnspecified}"</td>
- <td>It is unspecified whether the activity's main window resizes
- to make room for the soft keyboard, or whether the contents
- of the window pan to make the currentfocus visible on-screen.
+ <td>It is unspecified whether the activity's main window resizes
+ to make room for the soft keyboard, or whether the contents
+ of the window pan to make the current focus visible on-screen.
The system will automatically select one of these modes depending
- on whether the content of the window has any layout views that
- can scroll their contents. If there is such a view, the window
- will be resized, on the assumption that scrolling can make all
+ on whether the content of the window has any layout views that
+ can scroll their contents. If there is such a view, the window
+ will be resized, on the assumption that scrolling can make all
of the window's contents visible within a smaller area.
<p>
@@ -918,14 +941,14 @@
</p></td>
</tr></tr>
<td>"{@code adjustResize}"</td>
- <td>The activity's main window is always resized to make room for
+ <td>The activity's main window is always resized to make room for
the soft keyboard on screen.</td>
</tr></tr>
<td>"{@code adjustPan}"</td>
<td>The activity's main window is not resized to make room for the soft
- keyboard. Rather, the contents of the window are automatically
+ keyboard. Rather, the contents of the window are automatically
panned so that the current focus is never obscured by the keyboard
- and users can always see what they are typing. This is generally less
+ and users can always see what they are typing. This is generally less
desirable than resizing, because the user may need to close the soft
keyboard to get at and interact with obscured parts of the window.</td>
</tr>
@@ -938,12 +961,12 @@
<!-- ##api level indication## -->
<dt>introduced in:</dt>
-<dd>API Level 1 for all attributes except for
+<dd>API Level 1 for all attributes except for
<code><a href="#nohist">noHistory</a></code> and
-<code><a href="#wsoft">windowSoftInputMode</a></code>, which were added in API
+<code><a href="#wsoft">windowSoftInputMode</a></code>, which were added in API
Level 3.</dd>
<dt>see also:</dt>
-<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
+<dd><code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code>
<br/><code><a href="{@docRoot}guide/topics/manifest/activity-alias-element.html"><activity-alias></a></code></dd>
</dl>
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index 15092a0..18e479f 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -1,4 +1,4 @@
-page.title=<uses-sdk>
+fpage.title=<uses-sdk>
page.tags="api levels","sdk version","minsdkversion","targetsdkversion","maxsdkversion"
@jd:body
@@ -236,13 +236,13 @@
<tr><td><a href="{@docRoot}about/versions/android-4.2.html">Android 4.2, 4.2.2</a></td>
<td><a href="{@docRoot}sdk/api_diff/17/changes.html" title="Diff Report">17</a></td>
<td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}</td>
- <td><a href="{@docRoot}about/versions/jelly-bean.html">Platform
+ <td><a href="{@docRoot}about/versions/jelly-bean.html#android-42">Platform
Highlights</a></td></tr>
<tr><td><a href="{@docRoot}about/versions/android-4.1.html">Android 4.1, 4.1.1</a></td>
<td><a href="{@docRoot}sdk/api_diff/16/changes.html" title="Diff Report">16</a></td>
<td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN}</td>
- <td><a href="{@docRoot}about/versions/jelly-bean.html">Platform
+ <td><a href="{@docRoot}about/versions/jelly-bean.html#android-41">Platform
Highlights</a></td></tr>
<tr><td><a href="{@docRoot}about/versions/android-4.0.3.html">Android 4.0.3, 4.0.4</a></td>
diff --git a/docs/html/guide/topics/ui/accessibility/apps.jd b/docs/html/guide/topics/ui/accessibility/apps.jd
index 13b4538..da24d03 100644
--- a/docs/html/guide/topics/ui/accessibility/apps.jd
+++ b/docs/html/guide/topics/ui/accessibility/apps.jd
@@ -351,7 +351,7 @@
<li>If your application targets Android 4.0 (API level 14) and higher, override and implement the
accessibility methods listed above directly in your custom view class.</li>
<li>If your custom view is intended to be compatible with Android 1.6 (API Level 4) and above, add
-the Android <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>, revision 5 or
+the Android <a href="{@docRoot}tools/support-library/index.html">Support Library</a>, revision 5 or
higher, to your project. Then, within your custom view class, call the
{@link android.support.v4.view.ViewCompat#setAccessibilityDelegate
ViewCompat.setAccessibilityDelegate()} method to implement the accessibility methods
@@ -490,7 +490,7 @@
<p>The example code below shows how override these three methods by using
{@link android.support.v4.view.ViewCompat#setAccessibilityDelegate
ViewCompat.setAccessibilityDelegate()}. Note that this sample code requires that the Android
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> for API Level 4 (revision
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a> for API Level 4 (revision
5 or higher) is added to your project.</p>
<pre>
@@ -534,7 +534,7 @@
<p>In applications targeting Android 4.0 (API Level 14) and higher, you can implement these methods
directly in your custom view class. For another example of this approach, see the Android
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> (revision 5 or higher)
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a> (revision 5 or higher)
sample {@code AccessibilityDelegateSupportActivity} in
({@code <sdk>/extras/android/support/v4/samples/Support4Demos/}).</p>
@@ -594,7 +594,7 @@
example implementation of this accessibility feature, see
{@code AccessibilityNodeProviderActivity} in the ApiDemos sample project. You can implement a
virtual view hierarchy that is compatible with Android 1.6 and later by using the
- <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> with the
+ <a href="{@docRoot}tools/support-library/index.html">Support Library</a> with the
{@link android.support.v4.view.ViewCompat#getAccessibilityNodeProvider
ViewCompat.getAccessibilityNodeProvider()} method and providing an implementation with
{@link android.support.v4.view.accessibility.AccessibilityNodeProviderCompat}.</p>
diff --git a/docs/html/guide/topics/ui/accessibility/checklist.jd b/docs/html/guide/topics/ui/accessibility/checklist.jd
index 9473d1b..960cca2 100644
--- a/docs/html/guide/topics/ui/accessibility/checklist.jd
+++ b/docs/html/guide/topics/ui/accessibility/checklist.jd
@@ -73,7 +73,7 @@
your application, <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#custom-views">
implement accessibility interfaces</a> for your custom views and provide content descriptions.
For custom controls that are intended to be compatible with versions of Android back to 1.6,
- use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> to implement
+ use the <a href="{@docRoot}tools/support-library/index.html">Support Library</a> to implement
the latest accessibility features.</li>
<li><strong>No audio-only feedback:</strong> Audio feedback must always have a secondary
feedback mechanism to support users who are deaf or hard of hearing. For example, a sound alert
diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
index 2a6fe7a..4bd752f 100644
--- a/docs/html/guide/topics/ui/accessibility/services.jd
+++ b/docs/html/guide/topics/ui/accessibility/services.jd
@@ -55,7 +55,7 @@
<p>The ability for you to build and deploy accessibility services was introduced with Android 1.6
(API Level 4) and received significant improvements with Android 4.0 (API Level 14). The Android
- <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> was also updated with
+ <a href="{@docRoot}tools/support-library/index.html">Support Library</a> was also updated with
the release of Android 4.0 to provide support for these enhanced accessibility features back to
Android 1.6. Developers aiming for widely compatible accessibility services are encouraged to use
the Support Library and develop for the more advanced accessibility features introduced in
@@ -448,7 +448,7 @@
accessibility services that are compatible with Android 1.6 (API Level 4) and higher.</li>
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/accessibility/TaskBackService.html">TaskBackService</a>
- This service is based on the enhanced accessibility APIs introduced in Android 4.0 (API Level
-14). However, you can use the Android <a href="{@docRoot}tools/extras/support-library.html">Support
+14). However, you can use the Android <a href="{@docRoot}tools/support-library/index.html">Support
Libary</a> to substitute classes introduced in later API levels (e.g.,
{@link android.view.accessibility.AccessibilityRecord},
{@link android.view.accessibility.AccessibilityNodeInfo}
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index c5bbdbc..10ab61f 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1,9 +1,16 @@
page.title=Action Bar
page.tags="actionbar","menu"
-parent.title=User Interface
-parent.link=index.html
+
@jd:body
+
+<a class="notice-designers top" href="{@docRoot}design/patterns/actionbar.html">
+ <div>
+ <h3>Design Guide</h3>
+ <p>Action Bar</p>
+ </div>
+</a>
+
<div id="qv-wrapper">
<div id="qv">
@@ -12,23 +19,20 @@
<li><a href="#Adding">Adding the Action Bar</a>
<ol>
<li><a href="#Removing">Removing the action bar</a></li>
+ <li><a href="#Logo">Using a logo instead of an icon</a></li>
</ol>
</li>
<li><a href="#ActionItems">Adding Action Items</a>
<ol>
- <li><a href="#ChoosingActionItems">Choosing your action items</a></li>
+ <li><a href="#ActionEvents">Handling clicks on action items</a></li>
<li><a href="#SplitBar">Using split action bar</a></li>
</ol>
</li>
- <li><a href="#Home">Using the App Icon for Navigation</a>
- <ol>
- <li><a href="#Up">Navigating up</a></li>
- </ol>
- </li>
+ <li><a href="#Home">Navigating Up with the App Icon</a></li>
<li><a href="#ActionView">Adding an Action View</a>
<ol>
<li><a href="#ActionViewCollapsing">Handling collapsible action views</a></li>
- </ol>
+ </ol>
</li>
<li><a href="#ActionProvider">Adding an Action Provider</a>
<ol>
@@ -44,440 +48,290 @@
<li><a href="#ActionItemStyles">Action items</a></li>
<li><a href="#NavigationStyles">Navigation tabs</a></li>
<li><a href="#DropDownStyles">Drop-down lists</a></li>
- <li><a href="#AdvancedStyles">Advanced styling</a></li>
+ <li><a href="#StyleExample">Example theme</a></li>
</ol>
</li>
</ol>
<h2>Key classes</h2>
<ol>
- <li>{@link android.app.ActionBar}</li>
+ <li>{@link android.support.v7.app.ActionBar}</li>
<li>{@link android.view.Menu}</li>
- <li>{@link android.view.ActionProvider}</li>
</ol>
- <h2>Related samples</h2>
- <ol>
- <li><a
-href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a></li>
- <li><a
-href="{@docRoot}resources/samples/ActionBarCompat/index.html">Action Bar Compatibility</a></li>
- <li><a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/index.html#ActionBar">
-API Demos</a></li>
- </ol>
-
- <h2>See also</h2>
- <ol>
- <li><a
-href="{@docRoot}design/patterns/actionbar.html">Android Design: Action Bar</a></li>
- <li><a href="{@docRoot}guide/topics/ui/menus.html">Menus</a></li>
- <li><a href="{@docRoot}guide/practices/tablets-and-handsets.html">Supporting Tablets
-and Handsets</a></li>
- </ol>
</div>
</div>
-<p>The action bar is a window feature that identifies the application and user location, and
-provides user actions and navigation modes. You should use the action bar in most activities that
-need to prominently present user actions or global navigation, because the action bar offers users a
-consistent interface across applications and the system gracefully adapts the action bar's
-appearance for different screen configurations. You can control the behaviors and visibility of the
-action bar with the {@link android.app.ActionBar} APIs, which were added in Android 3.0 (API level
-11).</p>
+<p>The action bar is a window feature that identifies the user location, and
+provides user actions and navigation modes. Using the action bar offers your users a
+familiar interface across applications that the system gracefully adapts
+for different screen configurations.</p>
-<p>The primary goals of the action bar are to:</p>
+<img src="{@docRoot}images/ui/actionbar@2x.png" alt="" width="428" height="215" />
+<p class="img-caption"><strong>Figure 1.</strong> An action bar that includes the [1] app icon,
+[2] two action items, and [3] action overflow.</p>
+
+<p>The action bar provides several key functions:</p>
<ul>
- <li>Provide a dedicated space for identifying the application brand and user location.
- <p>This is accomplished with the app icon or logo on the left side and the activity title.
-You might choose to remove the activity title, however, if the current view is identified by a
-navigation label, such as the currently selected tab.</p></li>
-
- <li>Provide consistent navigation and view refinement across different applications.
- <p>The action bar provides built-in tab navigation for switching between <a
-href="{@docRoot}guide/components/fragments.html">fragments</a>. It also offers a drop-down
-list you can use as an alternative navigation mode or to refine the current view (such as to sort
-a list by different criteria).</p>
- </li>
-
- <li>Make key actions for the activity (such as "search", "create", "share", etc.) prominent and
-accessible to the user in a predictable way.
- <p>You can provide instant access to key user actions by placing items from the <a
-href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a> directly in the action bar,
-as "action items." Action items can also provide an "action view," which provides an embedded
-widget for even more immediate action behaviors. Menu items that are not promoted
-to an action item are available in the overflow menu, revealed by either the device <em>Menu</em>
-button
-(when available) or by an "overflow menu" button in the action bar (when the device does not
-include a <em>Menu</em> button).</p>
-</li>
+ <li>Provides a dedicated space for giving your app an identity and indicating the user's
+ location in the app.</li>
+ <li>Makes important actions prominent and accessible in a predictable way
+ (such as <em>Search</em>).</li>
+ <li>Supports consistent navigation and view switching within apps (with tabs or drop-down
+ lists).</li>
</ul>
-<img src="{@docRoot}images/ui/actionbar.png" alt="" width="440" />
-<p class="img-caption"><strong>Figure 1.</strong> Action bar from the <a
-href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app (on a
-landscape handset), showing the logo on the left, navigation tabs, and an action item on the
-right (plus the overflow menu button).</p>
+<p>For more information about the action bar's interaction patterns and design guidelines,
+see the <a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a>
+design guide.</p>
-<p class="note"><strong>Note:</strong> If you're looking for information about the contextual
-action bar for displaying contextual action items, see the <a
+<p>The {@link android.app.ActionBar} APIs were first added in Android 3.0 (API level 11) but they
+are also available in the <a href="{@docRoot}tools/support-library/index.html">Support Library</a>
+for compatibility with Android 2.1 (API level 7) and above.</p>
+
+<p><b>This guide focuses on how to use the
+support library's action bar</b>, but if your app supports <em>only</em> Android 3.0 or higher, you
+should use the {@link android.app.ActionBar} APIs in the framework. Most of the APIs are
+the same—but reside in a different package namespace—with a few exceptions to method
+names or signatures that are noted in the sections below.</p>
+
+
+<div class="caution">
+<p><strong>Caution:</strong> Be certain you import
+the {@code ActionBar} class (and related APIs) from the appropriate package:</p>
+<ul>
+<li>If supporting API levels <em>lower than</em> 11: <br>
+{@code import android.support.v7.app.ActionBar}</li>
+<li>If supporting <em>only</em> API level 11 and higher: <br>
+{@code import android.app.ActionBar}</li>
+</ul>
+</div>
+
+
+<p class="note"><strong>Note:</strong> If you're looking for information about the <em>contextual
+action bar</em> for displaying contextual action items, see the <a
href="{@docRoot}guide/topics/ui/menus.html#context-menu">Menu</a> guide.</p>
-<div class="note design">
-<p><strong>Action Bar Design</strong></p>
- <p>For design guidelines, read Android Design's <a
-href="{@docRoot}design/patterns/actionbar.html">Action Bar</a> guide.</p>
-</div>
-
-
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
- <h2>Remaining backward-compatible</h2>
-<p>If you want to provide an action bar in your application <em>and</em> remain compatible with
-versions of Android older than 3.0, you need to create the action bar in your
-activity's layout (because the {@link android.app.ActionBar} class is not available on older
-versions).</p>
-<p>To help you, the <a
-href="{@docRoot}resources/samples/ActionBarCompat/index.html">Action Bar Compatibility</a> sample
-app provides an API layer and action bar layout that allows your app to use some of the {@link
-android.app.ActionBar} APIs and also support older versions of Android by replacing the traditional
-title bar with a custom action bar layout.</p>
-</div>
-</div>
-
<h2 id="Adding">Adding the Action Bar</h2>
-<p>Beginning with Android 3.0 (API level 11), the action bar is included in all
-activities that use the {@link android.R.style#Theme_Holo Theme.Holo} theme (or one of its
+<p>As mentioned above, this guide focuses on how to use the {@link
+android.support.v7.app.ActionBar} APIs in the support library. So before you can add the action
+bar, you must set up your project with the <strong>appcompat v7</strong> support library by
+following the instructions in the <a href="{@docRoot}tools/support-library/setup.html">Support
+Library Setup</a>.</p>
+
+<p>Once your project is set up with the support library, here's how to add the action bar:</p>
+<ol>
+ <li>Create your activity by extending {@link android.support.v7.app.ActionBarActivity}.</li>
+ <li>Use (or extend) one of the {@link android.support.v7.appcompat.R.style#Theme_AppCompat
+ Theme.AppCompat} themes for your activity. For example:
+ <pre><activity android:theme="@style/Theme.AppCompat.Light" ... ></pre>
+ </li>
+</ol>
+
+<p>Now your activity includes the action bar when running on Android 2.1 (API level 7) or higher.
+</p>
+
+<div class="note">
+<p><b>On API level 11 or higher</b></p>
+<p>The action bar is included in all activities that use the
+{@link android.R.style#Theme_Holo Theme.Holo} theme (or one of its
descendants), which is the default theme when either the <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> or
<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>
-attribute is set to {@code "11"} or greater. For example:</p>
-
-<pre>
-<manifest ... >
- <uses-sdk android:minSdkVersion="4"
- <b>android:targetSdkVersion="11"</b> />
- ...
-</manifest>
-</pre>
-
-<p>In this example, the application requires a minimum version of API Level 4 (Android 1.6), but it
-also targets API level 11 (Android 3.0). This way, when the application runs on Android 3.0 or
-greater, the system applies the holographic theme to each activity, and thus, each activity includes
-the action bar.</p>
-
-<p>If you want to use {@link android.app.ActionBar} APIs, such as to add navigation modes and modify
-action bar styles, you should set the <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> to {@code
-"11"} or greater. If you want your app
-to support older versions of Android, there are ways to use a limited set of {@link
-android.app.ActionBar} APIs on devices that support API level 11 or higher, while still running
-on older versions. See the sidebox for information about remaining backward-compatible.</p>
+attribute is set to {@code "11"} or higher. If you don't want the action bar for an
+activity, set the activity theme to {@link android.R.style#Theme_Holo_NoActionBar
+Theme.Holo.NoActionBar}.</p>
+</div>
<h3 id="Removing">Removing the action bar</h3>
-<p>If you don't want the action bar for a particular activity, set the activity theme to
-{@link android.R.style#Theme_Holo_NoActionBar Theme.Holo.NoActionBar}. For example:</p>
+<p>You can hide the action bar at runtime by calling {@link android.support.v7.app.ActionBar#hide}.
+For example:</p>
<pre>
-<activity android:theme="@android:style/Theme.Holo.NoActionBar">
-</pre>
-
-<p>You can also hide the action bar at runtime by calling {@link android.app.ActionBar#hide}. For
-example:</p>
-
-<pre>
-ActionBar actionBar = {@link android.app.Activity#getActionBar()};
+ActionBar actionBar = {@link android.support.v7.app.ActionBarActivity#getSupportActionBar()};
actionBar.hide();
</pre>
-<p>When the action bar hides, the system adjusts your activity layout to fill all the
-screen space now available. You can bring the action bar back with {@link
-android.app.ActionBar#show()}.</p>
+<div class="note">
+<p><b>On API level 11 or higher</b></p>
+<p>Get the {@link android.app.ActionBar} with the {@link android.app.Activity#getActionBar}
+method.</p>
+</div>
+
+<p>When the action bar hides, the system adjusts your layout to fill the
+screen space now available. You can bring the action bar back by calling {@link
+android.support.v7.app.ActionBar#show()}.</p>
<p>Beware that hiding and removing the action bar causes your activity to re-layout in order to
-account for the space consumed by the action bar. If your activity regularly hides and shows the
-action bar (such as in the Android Gallery app), you might want to use overlay mode. Overlay mode
-draws the action bar on top of your activity layout rather than in its own area of the screen. This
+account for the space consumed by the action bar. If your activity often hides and shows the
+action bar, you might want to enable <em>overlay mode</em>. Overlay mode
+draws the action bar in front of your activity layout, obscuring the top portion. This
way, your layout remains fixed when the action bar hides and re-appears. To enable overlay mode,
-create a theme for your activity and set {@link android.R.attr#windowActionBarOverlay
-android:windowActionBarOverlay} to {@code true}. For more information, see the section about <a
+create a custom theme for your activity and set {@link
+android.support.v7.appcompat.R.attr#windowActionBarOverlay
+windowActionBarOverlay} to {@code true}. For more information, see the section below about <a
href="#Style">Styling the Action Bar</a>.</p>
-<p class="note"><strong>Tip:</strong> If you have a custom activity theme in which you'd like to
-remove the action bar, set the {@link android.R.styleable#Theme_windowActionBar
-android:windowActionBar} style property to {@code false}. However, if you remove the action bar
-using a theme, then the window will not allow the action bar at all, so you cannot add it
-later—calling {@link android.app.Activity#getActionBar()} will return null.</p>
+
+<h3 id="Logo">Using a logo instead of an icon</h3>
+
+<p>By default, the system uses your application icon in the action bar, as specified by the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#icon">{@code icon}</a>
+attribute in the <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+<application>}</a> or <a
+href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+<activity>}</a> element. However, if you also specify the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#logo">{@code logo}</a>
+attribute, then the action bar uses the logo image instead of the icon.</p>
+
+<p>A logo should usually be wider than the icon, but should not include unnecessary text. You
+should generally use a logo only when it represents your brand in a traditional format that users
+recognize. A good example is the YouTube app's logo—the logo represents the expected user
+brand, whereas the app's icon is a modified version that conforms to the square requirement
+for the launcher icon.</p>
+
<h2 id="ActionItems">Adding Action Items</h2>
-<p>Sometimes you might want to give users immediate access to an item from the <a
-href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a>. To do this, you can
-declare that the menu item should appear in the action bar as an "action item." An action item can
-include an icon and/or a text title. If a menu item does not appear as an action item, then the
-system places it in the overflow menu. The overflow menu is revealed either by the device
-<em>Menu</em>
-button (if provided by the device) or an additional button in the action bar (if the device does not
-provide the <em>Menu</em> button).</p>
-
-<div class="figure" style="width:359px">
- <img src="{@docRoot}images/ui/actionbar-item-withtext.png" height="57" alt="" />
- <p class="img-caption"><strong>Figure 2.</strong> Two action items with icon and text titles, and
-the overflow menu button.</p>
+<div class="figure" style="width:340px">
+ <img src="{@docRoot}images/ui/actionbar-item-withtext.png" width="340" alt="" />
+ <p class="img-caption"><strong>Figure 2.</strong> Action bar with three action buttons and
+the overflow button.</p>
</div>
-<p>When the activity first starts, the system populates the action bar and overflow menu by calling
-{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} for your activity. As
-discussed in the <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide, it's in
-this callback method that you should inflate an XML <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> that defines the
-menu items. For example:</p>
+<p>The action bar provides users access to the most important action
+items relating to the app's current
+context. Those that appear directly in the action bar with an icon and/or text are known
+as <em>action buttons</em>. Actions that can't fit in the action bar or aren't
+important enough are hidden in the action overflow.
+The user can reveal a list of the other actions by pressing the overflow button
+on the right side (or the device <em>Menu</em> button, if available).</p>
+
+<p>When your activity starts, the system populates the action items by calling your activity's
+{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method. Use this
+method to inflate a <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> that defines all the
+action items. For example, here's a menu resource defining a couple of menu items:</p>
+
+<p class="code-caption">res/menu/main_activity_actions.xml</p>
+<pre>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:id="@+id/action_search"
+ android:icon="@drawable/ic_action_search"
+ android:title="@string/action_search"/>
+ <item android:id="@+id/action_compose"
+ android:icon="@drawable/ic_action_compose"
+ android:title="@string/action_compose" />
+</menu>
+</pre>
+
+<p>Then in your activity's {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()}
+method, inflate the menu resource into the given {@link android.view.Menu}
+to add each item to the action bar:</p>
<pre>
@Override
public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.main_activity, menu);
- return true;
+ inflater.inflate(R.menu.main_activity_actions, menu);
+ return super.onCreateOptionsMenu(menu);
}
</pre>
-<p>In the XML file, you can request a menu item to appear as an action item by declaring {@code
-android:showAsAction="ifRoom"} for the {@code <item>} element. This way, the menu item appears
-in the action bar for quick access only <em>if there is room</em> available. If there's not
-enough room, the item appears in the overflow menu.</p>
+<p>To request that an item appear directly in the action bar
+as an action button, include {@code
+showAsAction="ifRoom"} in the {@code <item>} tag. For example:</p>
-<p>If your menu item supplies both a title and an icon—with the {@code android:title} and
-{@code android:icon} attributes—then the action item shows only the icon by default. If you
-want to display the text title, add {@code "withText"} to the {@code android:showAsAction}
+<pre>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ <strong>xmlns:yourapp="http://schemas.android.com/apk/res-auto"</strong> >
+ <item android:id="@+id/action_search"
+ android:icon="@drawable/ic_action_search"
+ android:title="@string/action_search"
+ <strong>yourapp:showAsAction="ifRoom"</strong> />
+ ...
+</menu>
+</pre>
+
+<p>If there's not enough room for the item in the action bar, it will appear in the action
+overflow.</p>
+
+
+<div class="note" id="XmlAttributes">
+<p><strong>Using XML attributes from the support library</strong></p>
+Notice that the {@code showAsAction} attribute above uses a custom namespace defined in the
+{@code <menu>} tag. This is necessary when using any XML attributes defined by the support
+library, because these attributes do not exist in the Android framework on older devices.
+So you must use your own namespace as a prefix for all attributes defined by the support library.
+</p>
+</div>
+
+<p>If your menu item supplies both a title and an icon—with the {@code title} and
+{@code icon} attributes—then the action item shows only the icon by default. If you
+want to display the text title, add {@code "withText"} to the {@code showAsAction}
attribute. For example:</p>
<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/menu_save"
- android:icon="@drawable/ic_menu_save"
- android:title="@string/menu_save"
- <b>android:showAsAction="ifRoom|withText"</b> />
-</menu>
+<item yourapp:showAsAction="ifRoom|withText" ... />
</pre>
<p class="note"><strong>Note:</strong> The {@code "withText"} value is a <em>hint</em> to the
action bar that the text title should appear. The action bar will show the title when possible, but
might not if an icon is available and the action bar is constrained for space.</p>
-<p>When the user selects an action item, your activity receives a call to
-{@link android.app.Activity#onOptionsItemSelected(MenuItem)
-onOptionsItemSelected()}, passing the ID supplied by the {@code android:id} attribute—the same
-callback received for all items in the options menu.</p>
-
-<p>It's important that you always define {@code android:title} for each menu item—even if you
-don't declare that the title appear with the action item—for three reasons:</p>
+<p>You should always define the {@code title} for each item even if you don't declare that
+the title appear with the action item, for the following reasons:</p>
<ul>
<li>If there's not enough room in the action bar for the action item, the menu item appears
-in the overflow menu and only the title appears.</li>
+in the overflow where only the title appears.</li>
<li>Screen readers for sight-impaired users read the menu item's title.</li>
<li>If the action item appears with only the icon, a user can long-press the item to reveal a
-tool-tip that displays the action item's title.</li>
+tool-tip that displays the action title.</li>
</ul>
-<p>The {@code android:icon} is always optional, but recommended. For icon design recommendations,
-see the <a href="{@docRoot}guide/practices/ui_guidelines/icon_design_action_bar.html">Action Bar
-Icon</a> design guidelines.</p>
+<p>The {@code icon} is optional, but recommended. For icon design recommendations,
+see the <a href="{@docRoot}design/style/iconography.html#action-bar">Iconography</a> design
+guide. You can also download a set of standard action bar icons (such as for Search or Discard)
+from the <a href="{@docRoot}design/downloads/index.html">Downloads</a> page.</p>
-<p class="note"><strong>Note:</strong> If you added the menu item from a fragment, via the {@link
-android.app.Fragment} class's {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu}
-callback, then the system calls the respective {@link
-android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method for that
-fragment when the user selects one of the fragment's items. However the activity gets a chance to
-handle the event first, so the system calls {@link
-android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} on the activity before
-calling the same callback for the fragment.</p>
-
-<p>You can also declare an item to <em>"always"</em> appear as an action item, instead of being
-placed in the overflow menu when space is limited. In most cases, you <strong>should not</strong>
-force an item to appear in the action bar by using the {@code "always"} value. However, you might
-need an item to always appear when it provides an <a href="#ActionView">action view</a> that does
-not offer a default action for the overflow menu. Beware that too
-many action items can create a cluttered UI and cause layout problems on devices with a narrow
-screen. It's best to instead use {@code "ifRoom"} to request that an item appear in the action
-bar, but allow the system to move it into the overflow menu when there's not enough room.</p>
-
-<p>For more information about creating the options menu that defines your action items, see the <a
-href="{@docRoot}guide/topics/ui/menus.html#options-menu">Menus</a> developer guide.</p>
-
-
-
-<h3 id="ChoosingActionItems">Choosing your action items</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
- <h4>Menu items vs. other app controls</h4>
- <p>As a general rule, all items in the <a
-href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a> (let alone action items)
-should have a global impact on the app, rather than affect only a small portion of the interface.
-For example, if you have a multi-pane layout and one pane shows a video while another lists all
-videos, the video player controls should appear within the pane containing the video (not in the
-action bar), while the action bar might provide action items to share the video or save the video to
-a favorites list.</p>
- <p>So, even before deciding whether a menu item should appear as an action item, be sure that
-the item has a global scope for the current activity. If it doesn't, then you should place it
-as a button in the appropriate context of the activity layout.</p>
-</div>
-</div>
-
-<p>You should carefully choose which items from your options menu should appear as action items by
-assessing a few key traits. In general, each action item should be <em>at least one</em>
-of the following:</p>
-
-<ol>
- <li><strong>Frequently used</strong>: It's an action that your users need seven out of ten visits
-or they use it several times in a row.
- <p>Example frequent actions: "New message" in the Messaging app and
-"Search" on Google Play.</p>
- </li>
-
- <li><strong>Important</strong>: It's an action that you need users to easily discover or, if it's
-not frequently used, it's important that it be effortless to perform in the few cases that users do
-need it.
- <p>Example important actions: "Add network" in Wi-Fi settings and "Switch to camera" in the
-Gallery app.</p>
- </li>
-
- <li><strong>Typical</strong>: It's an action that is typically provided in the action bar in
-similar apps, so your users expect to find it in yours.
- <p>Example typical actions: "Refresh" in an email or social app, and "New contact" in the
-People app.</p>
-</ol>
-
-<p>If you believe that more than four of your menu items can be justified as action items, then you
-should carefully consider their relative level of importance and try to set no more than four as
-action items (and do so using the {@code "ifRoom"} value to allow the system to put some back in the
-overflow menu when space is limited on smaller screens). Even if space is available on a wide
-screen, you should not create a long stream of action items that clutter the UI and appear like a
-desktop toolbar, so keep the number of action items to a minimum.</p>
-
-<p>Additionally, the following actions should never appear as action items: Settings, Help,
-Feedback, or similar. Always keep them in the overflow menu.</p>
-
-<p class="note"><strong>Note:</strong> Remember that not all devices provide a dedicated hardware
-button for Search, so if it's an important feature in your app, it should always appear as an
-action item (and usually as the first item, especially if you offer it with an <a
-href="#ActionView">action view</a>).</p>
-
-
-
-<h3 id="SplitBar">Using split action bar</h3>
-
-<p>When your application is running on Android 4.0 (API level 14) and higher, there's an extra mode
-available for the action bar called "split action bar." When you enable split action bar, a separate
-bar appears at the bottom of the screen to display all action items when the activity is running on
-a narrow screen (such as a portrait-oriented handset). Splitting the action bar to separate
-the action items ensures that a reasonable amount of space is available to display all your action
-items on a narrow screen, while leaving room for navigation and title elements at the top.</p>
-
-<p>To enable split action bar, simply add {@code uiOptions="splitActionBarWhenNarrow"} to your
-<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a> or
-<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
-manifest element.</p>
-
-<p>Be aware that Android adjusts the action bar's appearance in a variety of ways, based on the
-current screen size. Using split action bar is just one option that you can enable to allow the
-action bar to further optimize the user experience for different screen sizes. In doing so, you
-may also allow the action bar to collapse navigation tabs into the main action bar. That is, if you
-use <a href="#Tabs">navigation tabs</a> in your action bar, once the action items are
-separated on a narrow screen, the navigation tabs may be able to fit into the main action bar rather
-than be separated into the "stacked action bar." Specifically, if you've disabled the action bar
-icon and title (with {@link android.app.ActionBar#setDisplayShowHomeEnabled
-setDisplayShowHomeEnabled(false)} and {@link android.app.ActionBar#setDisplayShowTitleEnabled
-setDisplayShowTitleEnabled(false)}), then the navigation tabs collapse into the main action bar, as
-shown by the second device in figure 3.</p>
-
-<img src="{@docRoot}images/practices/actionbar-phone-splitaction.png" alt=""/>
-<p class="img-caption"><strong>Figure 3.</strong> Mock-ups of split action bar with navigation tabs
-on the left; with the app icon and title disabled on the right.</p>
-
-<p class="note"><strong>Note:</strong> Although the {@link android.R.attr#uiOptions
-android:uiOptions} attribute was added in Android 4.0 (API level 14), you can safely include it in
-your application even if your <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> is set to
-a value lower than {@code "14"} to remain compatible with older versions of Android. When running on
-older versions, the system simply ignores the XML attribute because it doesn't understand it. The
-only condition to including it in your manifest is that you must compile your application against a
-platform version that supports API level 14 or higher. Just be sure that you don't openly use other
-APIs in your application code that aren't supported by the version declared by your <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a>
-attribute—only XML attributes are safely ignored by older platforms.</p>
+<p>You can also use {@code "always"} to declare that an item always appear as an action button.
+However, you <strong>should not</strong> force an item to appear in the action bar this
+way. Doing so can create layout problems on devices with a narrow screen. It's best to instead
+use {@code "ifRoom"} to request that an item appear in the action bar, but allow the system to move
+it into the overflow when there's not enough room. However, it might be necessary to use this value
+if the item includes an <a href="#ActionView">action view</a> that cannot be collapsed and
+must always be visible to provide access to a critical feature.</p>
-<h2 id="Home">Using the App Icon for Navigation</h2>
+<h3 id="ActionEvents">Handling clicks on action items</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
- <h2>Using a logo instead of icon</h2>
-<p>By default, the system uses your application icon in the action bar, as specified by the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#icon">{@code android:icon}</a>
-attribute in the <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
-<application>}</a> or <a
-href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
-<activity>}</a> element. However, if you also specify the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#logo">{@code android:logo}</a>
-attribute, then the action bar uses the logo image instead of the icon.</p>
-<p>A logo should usually be wider than the icon, but should not include unnecessary text. You
-should generally use a logo only when it represents your brand in a traditional format that users
-recognize. A good example is the YouTube app's logo—the logo represents the expected user
-brand, whereas the app's icon is a modified version that conforms to the square requirement.</p>
-</div>
-</div>
-
-
-<p>By default, your application icon appears in the action bar on the left side. If you'd like,
-you can enable the icon to behave as an action item. In response to user action on the icon, your
-application should do one of two things:</p>
-
-<ul>
- <li>Go to the application "home" activity, or</li>
- <li>Navigate "up" the application's structural hierarchy</li>
-</ul>
-
-<p>When the user touches the icon, the system calls your activity's {@link
-android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method with the {@code
-android.R.id.home} ID. In response, you should either start the home activity or
-take the user one step up in your application's structural hierarchy.</p>
-
-<p>If you respond to the application icon by returning to the home activity, you should include
-the {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag in the {@link
-android.content.Intent}. With this flag, if the activity you're starting already exists in the
-current task, then all activities on top of it are destroyed and it is brought to the front.
-Adding this flag is often important because going "home" is an action that's equivalent to "going
-back" and you should usually not create a new instance of the home activity. Otherwise, you
-might end up with a long stack of activities in the current task with multiple instances of the
-home activity.</p>
-
-<p>For example, here's an implementation of {@link android.app.Activity#onOptionsItemSelected
-onOptionsItemSelected()} that returns to the application's "home" activity:</p>
+<p>When the user presses an action, the system calls your activity's {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method. Using the
+{@link android.view.MenuItem} passed to this method, you can identify the action by calling {@link
+android.view.MenuItem#getItemId()}. This returns the unique ID provided by the {@code <item>}
+tag's {@code id} attribute so you can perform the appropriate action. For example:</p>
<pre>
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle presses on the action bar items
switch (item.getItemId()) {
- case android.R.id.home:
- // app icon in action bar clicked; go home
- Intent intent = new Intent(this, HomeActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
+ case R.id.action_search:
+ openSearch();
+ return true;
+ case R.id.action_compose:
+ composeMessage();
return true;
default:
return super.onOptionsItemSelected(item);
@@ -485,221 +339,305 @@
}
</pre>
-<p>In case the user can enter the current activity from another application, you might also want to
-add the {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag. This flag ensures that, when the
-user navigates either "home" or "up", the new activity is <strong>not</strong> added to the current
-task, but instead started in a task that belongs to your application. For example, if the user
-starts an activity in your application through an intent invoked by another application, then
-selects the action bar icon to navigate home or up, the {@link
-android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag starts the activity in a task that belongs to
-your application (not the current task). The system either starts a new task with your new activity
-as the root activity or, if an existing task exists in the background with an instance of that
-activity, then that task is brought forward and the target activity receives {@link
-android.app.Activity#onNewIntent onNewIntent()}. So if your activity accepts intents from other
-applications (it declares any generic intent filters), you should usually add the {@link
-android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag to the intent:</p>
+<p class="note"><strong>Note:</strong> If you inflate menu items from a fragment, via the {@link
+android.app.Fragment} class's {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()}
+callback, the system calls {@link
+android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} for that
+fragment when the user selects one of those items. However, the activity gets a chance to
+handle the event first, so the system first calls {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} on the activity,
+before calling the same callback for the fragment. To ensure that any fragments in the
+activity also have a chance to handle the callback, always pass the call to the superclass
+as the default behavior instead of returning {@code false} when you do not handle the item.</p>
+
+
+
+<div class="figure" style="width:420px;margin-top:0">
+<img src="{@docRoot}images/ui/actionbar-splitaction@2x.png" alt="" width="420"/>
+<p class="img-caption"><strong>Figure 3.</strong> Mock-ups showing an action bar with
+tabs (left), then with split action bar (middle); and with the app icon and title disabled
+(right).</p>
+</p>
+</div>
+
+<h3 id="SplitBar">Using split action bar</h3>
+
+<p>Split action bar provides a separate
+bar at the bottom of the screen to display all action items when the activity is running on
+a narrow screen (such as a portrait-oriented handset).</p>
+
+<p>Separating the action items this way
+ensures that a reasonable amount of space is available to display all your action
+items on a narrow screen, while leaving room for navigation and title elements at the top.</p>
+
+<p>To enable split action bar when using the support library, you must do two things:</p>
+<ol>
+ <li>Add {@code uiOptions="splitActionBarWhenNarrow"} to each
+<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>
+element or to the
+<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
+element. This attribute is understood only by API level 14 and higher (it is ignored
+by older versions).</li>
+ <li>To support older versions, add a <a
+ href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+ element as a child of each
+ <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>
+ element that declares the same value for {@code "android.support.UI_OPTIONS"}.</li>
+</ol>
+
+<p>For example:</p>
<pre>
-intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+<manifest ...>
+ <activity uiOptions="splitActionBarWhenNarrow" ... >
+ <meta-data android:name="android.support.UI_OPTIONS"
+ android:value="splitActionBarWhenNarrow" />
+ </activity>
+</manifest>
</pre>
-<p>For more information about these flags and other back stack behaviors, read the <a
-href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a>
-developer guide.</p>
-<p class="note"><strong>Note:</strong> If you're using the icon to navigate to the home
-activity, beware that beginning with Android 4.0 (API level 14), you must explicitly enable the
-icon as an action item by calling {@link android.app.ActionBar#setHomeButtonEnabled
-setHomeButtonEnabled(true)} (in previous versions, the icon was enabled as an action item by
-default).</p>
+<p>Using split action bar also allows <a href="#Tabs">navigation tabs</a> to collapse into the
+main action bar if you remove the icon and title (as shown on the right in figure 3).
+To create this effect, disable the action bar
+icon and title with {@link android.support.v7.app.ActionBar#setDisplayShowHomeEnabled
+setDisplayShowHomeEnabled(false)} and {@link
+android.support.v7.app.ActionBar#setDisplayShowTitleEnabled setDisplayShowTitleEnabled(false)}.</p>
-<h3 id="Up">Navigating up</h3>
+<h2 id="Home">Navigating Up with the App Icon</h2>
-<div class="figure" style="width:230px;margin-top:-1em">
- <img src="{@docRoot}images/ui/actionbar-logo.png" alt="" />
- <p class="img-caption"><strong>Figure 4.</strong> The Email app's standard icon
-(left) and the "navigate up" icon (right). The system automatically adds the "up" indicator.</p>
+<a class="notice-designers" href="{@docRoot}design/patterns/navigation.html">
+ <div>
+ <h3>Design Guide</h3>
+ <p>Navigation with Back and Up</p>
+ </div>
+</a>
+
+<div class="figure" style="width:240px">
+ <img src="{@docRoot}images/ui/actionbar-up.png" width="240" alt="" />
+ <p class="img-caption"><strong>Figure 4.</strong> The <em>Up</em> button in Gmail.</p>
</div>
-<p>As a supplement to traditional "back" navigation—which takes the user to the previous
-screen in the task history—you can enable the action bar icon to offer "up"
-navigation, which should take the user one step up in your application's structural hierarchy. For
-instance, if the current screen is somewhere deep in the hierarchy of the application, touching the
-app icon should navigate upward one level, to the parent of the current screen.</p>
+<p>Enabling the app icon as an <em>Up</em> button allows the user to navigate your app based
+on the hierarchical relationships between screens. For instance, if screen A displays a list of
+items, and selecting an item leads to screen B, then
+screen B should include the <em>Up</em> button, which returns to screen A.</p>
-<p>For example, figure 5 illustrates how the BACK button behaves when the user navigates from one
-application to an activity belonging to a different application (specifically, when composing an
-email to a person selected from the People app).</p>
+<p class="note"><strong>Note:</strong> Up navigation is distinct from the back navigation provided
+by the system <em>Back</em> button. The <em>Back</em> button is used to navigate in reverse
+chronological order through the history of screens the user has recently worked with. It is
+generally based on the temporal relationships between screens, rather than the app's hierarchy
+structure (which is the basis for up navigation).</p>
-<img src="{@docRoot}images/ui/actionbar-navigate-back.png" alt="" />
-<p class="img-caption"><strong>Figure 5.</strong> The BACK button behavior
-after entering the Email app from the People (or Contacts) app.</p>
-
-<p>However, if the user wants to stay within the email application after composing the email,
-up navigation allows the user to navigate upward in the email application, rather than go back
-to the previous activity. Figure 6 illustrates this scenario, in which the user again comes into
-the email application, but presses the action bar icon to navigate up, rather than back.</p>
-
-<img src="{@docRoot}images/ui/actionbar-navigate-up.png" alt="" />
-<p class="img-caption"><strong>Figure 6.</strong> Example behavior for UP navigation after
-entering the Email app from the People app.</p>
-
-<div class="note design">
-<p><strong>Navigation Design</strong></p>
- <p>For more about how <em>Up</em> and <em>Back</em> navigation differ, read Android Design's <a
-href="{@docRoot}design/patterns/navigation.html">Navigation</a> guide.</p>
-</div>
-
-<p>To enable the icon for up navigation (which displays the "up" indicator next to the icon), call
-{@link android.app.ActionBar#setDisplayHomeAsUpEnabled setDisplayHomeAsUpEnabled(true)} on your
-{@link android.app.ActionBar}:</p>
+<p>To enable the app icon as an <em>Up</em> button, call {@link
+android.support.v7.app.ActionBar#setDisplayHomeAsUpEnabled setDisplayHomeAsUpEnabled()}.
+For example:</p>
<pre>
+@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_details);
- setContentView(R.layout.main);
- ActionBar actionBar = getActionBar();
+ ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
...
}
</pre>
-<p>When the user touches the icon, the system calls your activity's {@link
-android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method with the {@code
-android.R.id.home} ID, as shown in the above section about <a href="#Home">Using the App Icon
-for Navigation</a>.</p>
+<p>Now the icon in the action bar appears with the <em>Up</em> caret (as shown in figure 4).
+However, it won't do anything by default. To specify the activity to open when the
+user presses <em>Up</em> button, you have two options:</p>
-<p>Remember to use the {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag in the {@link
-android.content.Intent}, so that you don't create a new instance of the parent activity if one
-already exists. For instance, if you don't use the {@link
-android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} flag, then after navigating up, the BACK button will
-actually take the user "forward", with respect to the application structure, which would be
-strange.</p>
+<ul>
+ <li><b>Specify the parent activity in the manifest file.</b>
+ <p>This is the best option when <strong>the parent activity is always the same</strong>. By
+declaring in the manifest which activity is the parent, the action bar automatically performs the
+correct action when the user presses the <em>Up</em> button.</p>
-<p class="note"><strong>Note:</strong> If there are many paths that the user could have taken to
-reach the current activity within your application, the up icon should navigate backward along the
-path the user actually followed to get to the current activity.</p>
+ <p>Beginning in Android 4.1 (API level 16), you can declare the parent with the <a href=
+"{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code parentActivityName}</a>
+attribute in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+<activity>}</a> element.</p>
+ <p>To support older devices with the support library, also
+include a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code
+<meta-data>}</a> element that specifies
+the parent activity as the value for {@code android.support.PARENT_ACTIVITY}. For example:</p>
+<pre>
+<application ... >
+ ...
+ <!-- The main/home activity (has no parent activity) -->
+ <activity
+ android:name="com.example.myfirstapp.MainActivity" ...>
+ ...
+ </activity>
+ <!-- A child of the main activity -->
+ <activity
+ android:name="com.example.myfirstapp.DisplayMessageActivity"
+ android:label="@string/title_activity_display_message"
+ android:parentActivityName="com.example.myfirstapp.MainActivity" >
+ <!-- Parent activity meta-data to support API level 7+ -->
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="com.example.myfirstapp.MainActivity" />
+ </activity>
+</application>
+</pre>
+ <p>Once the parent activity is specified in the manifest like this and you enable the <em>Up</em>
+ button with {@link
+android.support.v7.app.ActionBar#setDisplayHomeAsUpEnabled setDisplayHomeAsUpEnabled()}, your work
+is done and the action bar properly navigates up.</p>
+ </li>
+
+
+ <li><strong>Or, override {@link
+android.support.v7.app.ActionBarActivity#getSupportParentActivityIntent()} and {@link
+android.support.v7.app.ActionBarActivity#onCreateSupportNavigateUpTaskStack
+onCreateSupportNavigateUpTaskStack()} in your activity</strong>.</li>
+
+ <p>This is appropriate when <strong>the parent activity may be different</strong> depending
+ on how the user arrived at the current screen. That is, if there are many paths that the user
+ could have taken to reach the current screen, the <em>Up</em> button should navigate
+ backward along the path the user actually followed to get there.</p>
+
+ <p>The system calls {@link
+android.support.v7.app.ActionBarActivity#getSupportParentActivityIntent()} when the user presses
+the <em>Up</em> button while navigating your app (within your app's own task). If the activity that
+should open upon up navigation differs depending on how the user arrived at the current location,
+then you should override this method to return the {@link
+android.content.Intent} that starts the appropriate parent activity.</p>
+
+ <p>The system calls {@link
+android.support.v7.app.ActionBarActivity#onCreateSupportNavigateUpTaskStack
+onCreateSupportNavigateUpTaskStack()} for your activity when the user presses the <em>Up</em>
+button while your activity is running in a task that does <em>not</em> belong to your app. Thus,
+you must use the {@link android.support.v4.app.TaskStackBuilder} passed to this method to construct
+the appropriate back stack that should be synthesized when the user navigates up.</p>
+
+ <p>Even if you override {@link
+android.support.v7.app.ActionBarActivity#getSupportParentActivityIntent()} to specify up navigation
+as the user navigates your app, you can avoid the need to implement {@link
+android.support.v7.app.ActionBarActivity#onCreateSupportNavigateUpTaskStack
+onCreateSupportNavigateUpTaskStack()} by declaring "default" parent activities in the manifest file
+as shown above. Then the default implementation of {@link
+android.support.v7.app.ActionBarActivity#onCreateSupportNavigateUpTaskStack
+onCreateSupportNavigateUpTaskStack()} will synthesize a back stack based on the parent activities
+declared in the manifest.</p>
+
+ </li>
+</ul>
+
+<p class="note"><strong>Note:</strong>
+If you've built your app hierarchy using a series of fragments instead of multiple
+activities, then neither of the above options will work. Instead, to navigate up through your
+fragments, override {@link android.support.v7.app.ActionBarActivity#onSupportNavigateUp()}
+to perform the appropriate fragment transaction—usually by popping
+the current fragment from the back stack by calling {@link
+android.support.v4.app.FragmentManager#popBackStack()}.</p>
+
+<p>For more information about implementing <em>Up</em> navigation, read
+<a href="{@docRoot}training/implementing-navigation/ancestral.html">Providing Up Navigation</a>.</p>
<h2 id="ActionView">Adding an Action View</h2>
-<div class="figure" style="width:300px;margin-top:-1em">
- <img src="/images/ui/actionbar-searchview.png" alt="" />
- <p class="img-caption"><strong>Figure 7.</strong> An action bar with a collapsed action
-view for Search (top), then expanded action view with the <code><a
-href="/reference/android/widget/SearchView.html">SearchView</a></code> widget (bottom).</p>
+<div class="figure" style="width:340px">
+<img src="/images/ui/actionbar-searchview@2x.png" alt="" width="340" />
+<p class="img-caption"><strong>Figure 5.</strong> An action bar with a collapsible
+{@link android.support.v7.widget.SearchView}.</p>
</div>
-<p>An action view is a widget that appears in the action bar as a substitute for an action item's
-button. For example, if you have an item in the options menu for "Search," you can add an action
-view that replaces the button with a {@link android.widget.SearchView} widget, as shown in figure
-7.</p>
+<p>An <em>action view</em> is a widget that appears in the action bar as a substitute for an action
+button. An action view provides fast access to rich actions without changing activities or
+fragments, and without replacing the action bar. For example, if you have an action for Search, you
+can add an action view to
+embeds a {@link android.support.v7.widget.SearchView} widget in the action bar, as shown in figure
+5.</p>
-<p>To declare an action view for an item in your <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, use either the {@code
-android:actionLayout} or {@code android:actionViewClass} attribute to specify either a layout
-resource or widget class to use, respectively. For example:</p>
+<p>To declare an action view, use either the {@code
+actionLayout} or {@code actionViewClass} attribute to specify either a layout
+resource or widget class to use, respectively. For example, here's how to add
+the {@link android.support.v7.widget.SearchView} widget:</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/menu_search"
- android:title="@string/menu_search"
- android:icon="@drawable/ic_menu_search"
- android:showAsAction="ifRoom|collapseActionView"
- <b>android:actionViewClass="android.widget.SearchView"</b> />
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
+ <item android:id="@+id/action_search"
+ android:title="@string/action_search"
+ android:icon="@drawable/ic_action_search"
+ yourapp:showAsAction="ifRoom|collapseActionView"
+ <b>yourapp:actionViewClass="android.support.v7.widget.SearchView"</b> />
</menu>
</pre>
-<p>Notice that the {@code android:showAsAction} attribute also includes {@code
-"collapseActionView"}. This is optional and declares that the action view should be collapsed into a
-button. When the user selects the button, the action view expands. Otherwise, the action view is
-visible by default and might consume valuable action bar space even when the user is not using it.
-For more information, see the next section about <a href="#ActionViewCollapsing">Handling
-collapsible action views</a>.</p>
+<p>Notice that the {@code showAsAction} attribute also includes the {@code "collapseActionView"}
+value. This is optional and declares that the action view should be collapsed into a
+button. (This behavior is explained further in the following section about
+<a href="#ActionViewCollapsing">Handling collapsible action views</a>.)</p>
-<p>If you need to add some event hooks to your action view, you can do so during the {@link
-android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback. You can acquire elements
-in an action view by calling {@link android.view.Menu#findItem findItem()} with the ID of the menu
-item, then call {@link android.view.MenuItem#getActionView}. For
-example, the search widget from the above sample is acquired like this:</p>
+<p>If you need to configure the action view (such as to add event listeners), you can do so during
+the {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} callback. You can
+acquire the action view object by calling the static method {@link
+android.support.v4.view.MenuItemCompat#getActionView MenuItemCompat.getActionView()} and passing it
+the corresponding {@link android.view.MenuItem}. For example, the search widget from the above
+sample is acquired like this:</p>
+
<pre>
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.options, menu);
- SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
+ getMenuInflater().inflate(R.menu.main_activity_actions, menu);
+ MenuItem searchItem = menu.findItem(R.id.action_search);
+ SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
// Configure the search info and add any event listeners
...
return super.onCreateOptionsMenu(menu);
}
</pre>
+<div class="note">
+<p><b>On API level 11 or higher</b></p>
+<p>Get the action view by calling {@link android.view.MenuItem#getActionView} on the
+corresponding {@link android.view.MenuItem}:</p>
+<pre>menu.findItem(R.id.action_search).getActionView()</pre>
+</div>
+
<p>For more information about using the search widget, see <a
href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.</p>
+
<h3 id="ActionViewCollapsing">Handling collapsible action views</h3>
-<div class="sidebox-wrapper">
-<div class="sidebox">
- <h3>Supporting Android 3.0 with an action view</h3>
- <p>The {@code "collapseActionView"} option was added with Android 4.0 (API level 14). However, if
-your application supports older versions, you should
-still declare {@code "collapseActionView"} in order to better support smaller screens.
-Devices running Android 4.0 and higher will show the action view collapsed, while older versions
-work as designed otherwise.</p>
- <p>Adding this value requires that you set your build target to Android 4.0 or higher in order to
-compile. Older versions of Android ignore the {@code "collapseActionView"} value because they don't
-understand it. Just be sure not to use other APIs in your source code that are not supported in the
-version declared by your <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-minSdkVersion}</a>, unless you add the appropriate version check at runtime.</p>
-</div>
-</div>
-
-
-<p>Action views allow you to provide fast access to rich actions without changing activities or
-fragments, or replacing the action bar. However, it might not be appropriate to make an action view
-visible by default. To preserve the action bar space (especially when running on smaller screens),
-you can collapse your action view into an action item button. When the user selects the
-button, the action view appears in the action bar. When collapsed, the system might place the item
-into the overflow menu if you've defined {@code android:showAsAction} with {@code "ifRoom"}, but the
-action view still appears in the action bar when the user selects the item. You can make your action
-view collapsible by adding {@code "collapseActionView"} to the {@code android:showAsAction}
+<p>To preserve the action bar space, you can collapse your action view into an action button.
+When collapsed, the system might place the action
+into the action overflow, but the
+action view still appears in the action bar when the user selects it. You can make your action
+view collapsible by adding {@code "collapseActionView"} to the {@code showAsAction}
attribute, as shown in the XML above.</p>
-<p>Because the system will expand the action view when the user selects the item, you
+<p>Because the system expands the action view when the user selects the action, you
<em>do not</em> need to respond to the item in the {@link
-android.app.Activity#onOptionsItemSelected onOptionsItemSelected} callback. The system still calls
-{@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} when the user selects it,
-but the system will always expand the action view unless you return {@code true} (indicating
-you've handled the event instead).</p>
+android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback. The system still calls
+{@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()}, but if
+you return {@code true} (indicating you've handled the event instead), then the
+action view will <em>not</em> expand.</p>
-<p>The system also collapses your action view when the user selects the "up" icon in the action
-bar or presses the BACK button.</p>
-
-<p>If necessary, you can expand or collapse the action view in your own code by calling {@link
-android.view.MenuItem#expandActionView()} and {@link android.view.MenuItem#collapseActionView()} on
-the {@link android.view.MenuItem}.</p>
-
-<p class="note"><strong>Note:</strong> Although collapsing your action view is optional, we
-recommend that you always collapse your action view if it includes {@link
-android.widget.SearchView}. Also be aware that some devices provide a dedicated SEARCH button and
-you should expand your search action view if the user presses the SEARCH button. Simply override
-your activity's {@link android.app.Activity#onKeyUp onKeyUp()} callback method, listen for the
-{@link android.view.KeyEvent#KEYCODE_SEARCH} event, then call {@link
-android.view.MenuItem#expandActionView()}.</p>
+<p>The system also collapses your action view when the user presses the <em>Up</em> button
+or <em>Back</em> button.</p>
<p>If you need to update your activity based on the visibility of your action view, you can receive
-callbacks when it's expanded and collapsed by defining an {@link
-android.view.MenuItem.OnActionExpandListener OnActionExpandListener} and registering it with {@link
-android.view.MenuItem#setOnActionExpandListener setOnActionExpandListener()}. For example:</p>
+callbacks when the action is expanded and collapsed by defining an {@link
+android.support.v4.view.MenuItemCompat.OnActionExpandListener OnActionExpandListener} and
+passing it to {@link android.support.v4.view.MenuItemCompat#setOnActionExpandListener
+setOnActionExpandListener()}. For example:</p>
+
<pre>
@Override
@@ -708,7 +646,9 @@
MenuItem menuItem = menu.findItem(R.id.actionItem);
...
- menuItem.setOnActionExpandListener(new OnActionExpandListener() {
+ // When using the support library, the setOnActionExpandListener() method is
+ // static and accepts the MenuItem object as an argument
+ MenuItemCompat.setOnActionExpandListener(menuItem, new OnActionExpandListener() {
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Do something when collapsed
@@ -729,165 +669,168 @@
<h2 id="ActionProvider">Adding an Action Provider</h2>
-<div class="figure" style="width:200px">
- <img src="{@docRoot}images/ui/actionbar-shareaction.png" alt="" />
- <p class="img-caption"><strong>Figure 8.</strong> Screenshot from the Gallery app, with the
- {@link android.widget.ShareActionProvider} submenu expanded to show share targets.</p>
+<div class="figure" style="width:240px">
+ <img src="{@docRoot}images/ui/actionbar-shareaction@2x.png" alt="" width="240" />
+ <p class="img-caption"><strong>Figure 6.</strong> An action bar with
+ {@link android.widget.ShareActionProvider} expanded to show share targets.</p>
</div>
-<p>Similar to an <a href="#ActionView">action view</a>, an action provider (defined by the {@link
-android.view.ActionProvider} class) replaces an action item with a customized layout, but it also
-takes control of all the item's behaviors. When you declare an action provider for a menu
-item in the action bar, it not only controls the appearance of the item in the action bar with a
-custom layout, but also handles the default event for the menu item when it appears in the overflow
-menu. It can also provide a submenu from either the action bar or the overflow menu.</p>
+<p>Similar to an <a href="#ActionView">action view</a>, an <em>action provider</em>
+replaces an action button with a customized layout. However,
+unlike an action view, an action provider takes control of all the action's behaviors
+and an action provider can display a submenu when pressed.</p>
-<p>For example, the {@link android.widget.ShareActionProvider} is an extension of {@link
-android.view.ActionProvider} that facilitates a “share" action by showing a list of available share
-targets from the action bar. Instead of using a
-traditional action item that invokes the {@link android.content.Intent#ACTION_SEND} intent, you can
-declare an instance of {@link android.widget.ShareActionProvider} to handle an action item. This
-action provider presents an action view with a drop-down list of applications that handle
-the {@link android.content.Intent#ACTION_SEND} intent, even when the menu item appears in the
-overflow menu. Hence, when you use an action provider such as this one, you don't
-have to handle user events on the menu item.</p>
+<p>To declare an action provider, supply the {@code actionViewClass} attribute in the
+menu {@code <item>} tag with a fully-qualified class name for an
+{@link android.support.v4.view.ActionProvider}.</p>
-<p>To declare an action provider for an action item, define the {@code android:actionProviderClass}
-attribute for the appropriate the {@code <item>} element in your <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, using the
-fully-qualified class name of the action provider. For example:</p>
+<p>You can build your own action provider by extending the {@link
+android.support.v4.view.ActionProvider} class, but Android provides some pre-built action providers
+such as {@link android.support.v7.widget.ShareActionProvider}, which facilitates a "share" action
+by showing a list of possible apps for sharing directly in the action bar (as shown in figure
+6).</p>
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/menu_share"
- android:title="@string/share"
- android:showAsAction="ifRoom"
- <strong>android:actionProviderClass="android.widget.ShareActionProvider"</strong> />
- ...
-</menu>
-</pre>
+<p>Because each {@link android.support.v4.view.ActionProvider} class defines its own action
+behaviors, you don't need to listen for the action in the {@link
+android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method. If necessary though,
+you can still listen for the click event in the {@link android.app.Activity#onOptionsItemSelected
+onOptionsItemSelected()} method in case you need to simultaneously perform another action. But be
+sure to return {@code false} so that the the action provider still receives the {@link
+android.support.v4.view.ActionProvider#onPerformDefaultAction()} callback to perform its intended
+action.</p>
-<p>In this example, the {@link android.widget.ShareActionProvider} is used as the action provider.
-At this point, the action provider officially takes control of the menu item and handles both
-its appearance and behavior in the action bar and its behavior in the overflow menu. You must
-still provide a text title for the item to be used in the overflow menu.</p>
-<p>Although the action provider can perform the default action for the menu item when it appears in
-the overflow menu, your activity (or fragment) can override that behavior by
-also handling the click event from the {@link android.app.Activity#onOptionsItemSelected
-onOptionsItemSelected()} callback method. If you do not handle the event in that callback, then
-the action provider receives the {@link android.view.ActionProvider#onPerformDefaultAction()}
-callback to handle the event. However, if the action provider provides a submenu, then your
-activity will not receive the {@link android.app.Activity#onOptionsItemSelected
-onOptionsItemSelected()} callback, because the submenu is shown instead of invoking the default
-menu item behavior when selected.</p>
+<p>However, if the action provider provides a submenu of actions, then your
+activity does not receive a call to {@link android.app.Activity#onOptionsItemSelected
+onOptionsItemSelected()} when the user opens the list or selects one of the submenu items.</p>
<h3 id="ShareActionProvider">Using the ShareActionProvider</h3>
-<p>If you want to provide a "share" action in your action bar by leveraging other applications
-installed on the device (for example, to share a photo using a messaging or social app), then using
-{@link android.widget.ShareActionProvider} is an effective way to do so, rather than adding an
-action item that invokes the {@link android.content.Intent#ACTION_SEND} intent. When
-you use {@link android.widget.ShareActionProvider} for an action item, it presents an action view
-with a drop-down list of applications that handle the {@link android.content.Intent#ACTION_SEND}
-intent (as shown in figure 8).</p>
+<p>To add a "share" action with {@link android.support.v7.widget.ShareActionProvider},
+define the {@code actionProviderClass} for an {@code <item>} tag with
+the {@link android.support.v7.widget.ShareActionProvider} class. For example:</p>
-<p>All the logic for creating the submenu, populating it with share targets, and handling click
-events (including when the item appears in the overflow menu) is implemented by the {@link
-android.widget.ShareActionProvider}—the only code you need to write is to declare the action
-provider for the menu item and specify the share intent.</p>
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
+ <item android:id="@+id/action_share"
+ android:title="@string/share"
+ yourapp:showAsAction="ifRoom"
+ <strong>yourapp:actionProviderClass="android.support.v7.widget.ShareActionProvider"</strong>
+ />
+ ...
+</menu>
+</pre>
-<p>By default, the {@link android.widget.ShareActionProvider} retains a ranking for each
-share target based on how often the user selects each one. The share targets used more frequently
-appear at the top of the drop-down list and the target used most often appears directly in the
-action bar as the default share target. By default, the ranking information is
-saved in a private file with a name specified by {@link
-android.widget.ShareActionProvider#DEFAULT_SHARE_HISTORY_FILE_NAME}. If you use the {@link
-android.widget.ShareActionProvider} or an extension of it for only one type of action, then you
-should continue to use this default history file and there's nothing you need to do. However, if you
-use {@link android.widget.ShareActionProvider} or an extension of it for multiple actions with
-semantically different meanings, then each {@link android.widget.ShareActionProvider} should specify
-its own history file in order to maintain its own history. To specify a
-different history file for the {@link android.widget.ShareActionProvider}, call {@link
-android.widget.ShareActionProvider#setShareHistoryFileName setShareHistoryFileName()} and provide
-an XML file name (for example, {@code "custom_share_history.xml"}).</p>
+<p>Now the action provider takes control of the action item and handles both
+its appearance and behavior. But you must
+still provide a title for the item to be used when it appears in the action overflow.</p>
-<p class="note"><strong>Note:</strong> Although the {@link android.widget.ShareActionProvider} ranks
-share targets based on frequency of use, the behavior is extensible and extensions of {@link
-android.widget.ShareActionProvider} can perform different behaviors and ranking based on the history
-file (if appropriate).</p>
+<p>The only thing left to do is define
+the {@link android.content.Intent} you want to use for sharing. To do so, edit
+your {@link
+android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method to call {@link
+android.support.v4.view.MenuItemCompat#getActionProvider MenuItemCompat.getActionProvider()}
+and pass it the {@link android.view.MenuItem} holding the action provider. Then call {@link
+android.support.v7.widget.ShareActionProvider#setShareIntent setShareIntent()} on the
+returned {@link android.support.v7.widget.ShareActionProvider} and pass it an
+{@link android.content.Intent#ACTION_SEND} intent with the appropriate content attached.</p>
-<p>To add {@link android.widget.ShareActionProvider}, simply define the {@code
-android:actionProviderClass} attribute with {@code "android.widget.ShareActionProvider"}, as shown
-in the XML example above. The only thing left to do is define
-the {@link android.content.Intent} you want to use for sharing. To do so, you must call {@link
-android.view.MenuItem#getActionProvider} to retrieve the {@link android.widget.ShareActionProvider}
-that's associated with a {@link android.view.MenuItem}, then call {@link
-android.widget.ShareActionProvider#setShareIntent setShareIntent()}.</p>
+<p>You should call {@link
+android.support.v7.widget.ShareActionProvider#setShareIntent setShareIntent()} once during {@link
+android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} to initialize the share action,
+but because the user context might change, you must update the intent any time the shareable
+content changes by again calling {@link
+android.support.v7.widget.ShareActionProvider#setShareIntent setShareIntent()}.</p>
-<p>If the format for the share intent depends on the selected item or other variables that change
-during the activity lifecycle, you should save the {@link android.widget.ShareActionProvider} in a
-member field and update it by calling {@link android.widget.ShareActionProvider#setShareIntent
-setShareIntent()} as necessary. For example:</p>
+<p>For example:</p>
<pre>
private ShareActionProvider mShareActionProvider;
-...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- mShareActionProvider = (ShareActionProvider) menu.findItem(R.id.menu_share).getActionProvider();
+ getMenuInflater().inflate(R.menu.main_activity_actions, menu);
- // If you use more than one ShareActionProvider, each for a different action,
- // use the following line to specify a unique history file for each one.
- // mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
+ // Set up ShareActionProvider's default share intent
+ MenuItem shareItem = menu.findItem(R.id.action_share);
+ mShareActionProvider = (ShareActionProvider)
+ MenuItemCompat.getActionProvider(shareItem);
+ mShareActionProvider.setShareIntent(getDefaultIntent());
- // Set the default share intent
- mShareActionProvider.setShareIntent(getDefaultShareIntent());
-
- return true;
+ return super.onCreateOptionsMenu(menu);
}
-// When you need to update the share intent somewhere else in the app, call
-// mShareActionProvider.{@link android.widget.ShareActionProvider#setShareIntent setShareIntent()}
+
+/** Defines a default (dummy) share intent to initialize the action provider.
+ * However, as soon as the actual content to be used in the intent
+ * is known or changes, you must update the share intent by again calling
+ * mShareActionProvider.{@link android.support.v7.widget.ShareActionProvider#setShareIntent setShareIntent()}
+ */
+private Intent getDefaultIntent() {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("image/*");
+ return intent;
+}
</pre>
-<p>The {@link android.widget.ShareActionProvider} now handles all user interaction with the item and
-you <em>do not</em> need to handle click events from the {@link
+<p>The {@link android.support.v7.widget.ShareActionProvider} now handles all user interaction with
+the item and you <em>do not</em> need to handle click events from the {@link
android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} callback method.</p>
-<p>For a sample using the share action provider, see
-<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ActionBarShareActionProviderActivity.html"
->ActionBarShareActionProviderActivity</a>.
+
+<p>By default, the {@link android.support.v7.widget.ShareActionProvider} retains a ranking for each
+share target based on how often the user selects each one. The share targets used more frequently
+appear at the top of the drop-down list and the target used most often appears directly in the
+action bar as the default share target. By default, the ranking information is saved in a private
+file with a name specified by {@link
+android.support.v7.widget.ShareActionProvider#DEFAULT_SHARE_HISTORY_FILE_NAME}. If you use the
+{@link android.support.v7.widget.ShareActionProvider} or an extension of it for only one type of
+action, then you should continue to use this default history file and there's nothing you need to
+do. However, if you use {@link android.support.v7.widget.ShareActionProvider} or an extension of it
+for multiple actions with semantically different meanings, then each {@link
+android.support.v7.widget.ShareActionProvider} should specify its own history file in order to
+maintain its own history. To specify a different history file for the {@link
+android.support.v7.widget.ShareActionProvider}, call {@link
+android.support.v7.widget.ShareActionProvider#setShareHistoryFileName setShareHistoryFileName()}
+and provide an XML file name (for example, {@code "custom_share_history.xml"}).</p>
+
+
+<p class="note"><strong>Note:</strong> Although the {@link
+android.support.v7.widget.ShareActionProvider} ranks share targets based on frequency of use, the
+behavior is extensible and extensions of {@link android.support.v7.widget.ShareActionProvider} can
+perform different behaviors and ranking based on the history file (if appropriate).</p>
+
<h3 id="CreatingActionProvider">Creating a custom action provider</h3>
-<p>When you want to create an action view that has dynamic behaviors and a default action in the
-overflow menu, extending {@link android.view.ActionProvider} to define those behaviors is a good
-solution. Creating your own action provider offers you an organized and reusable component, rather
-than handling the various action item transformations and behaviors in your fragment or activity
-code. As shown in the previous section, Android provides one implementation of {@link
-android.view.ActionProvider} for share actions: the {@link android.widget.ShareActionProvider}.</p>
+<p>Creating your own action provider allows you to re-use and manage dynamic action item
+behaviors in a self-contained module, rather than handle action item transformations and
+behaviors in your fragment or activity
+code. As shown in the previous section, Android already provides an implementation of {@link
+android.support.v4.view.ActionProvider} for share actions: the {@link
+android.support.v7.widget.ShareActionProvider}.</p>
-<p>To create your own, simply extend the {@link android.view.ActionProvider} class and implement
+<p>To create your own action provider for a different action, simply extend the
+{@link android.support.v4.view.ActionProvider} class and implement
its callback methods as appropriate. Most importantly, you should implement the following:</p>
<dl>
- <dt>{@link android.view.ActionProvider#ActionProvider ActionProvider()}</dt>
+ <dt>{@link android.support.v4.view.ActionProvider#ActionProvider ActionProvider()}</dt>
<dd>This constructor passes you the application {@link android.content.Context}, which you
should save in a member field to use in the other callback methods.</dd>
- <dt>{@link android.view.ActionProvider#onCreateActionView()}</dt>
+ <dt>{@link android.support.v4.view.ActionProvider#onCreateActionView(MenuItem)}</dt>
<dd>This is where you define the action view for the item. Use the {@link
android.content.Context} acquired from the constructor to instantiate a {@link
android.view.LayoutInflater} and inflate your action view layout from an XML resource, then hook
up event listeners. For example:
<pre>
-public View onCreateActionView() {
+public View onCreateActionView(MenuItem forItem) {
// Inflate the action view to be shown on the action bar.
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
View view = layoutInflater.inflate(R.layout.action_provider, null);
@@ -903,18 +846,21 @@
</pre>
</dd>
- <dt>{@link android.view.ActionProvider#onPerformDefaultAction()}</dt>
- <dd>The system calls this when the menu item is selected from the overflow menu and the
+ <dt>{@link android.support.v4.view.ActionProvider#onPerformDefaultAction()}</dt>
+ <dd>The system calls this when the menu item is selected from the action overflow and the
action provider should perform a default action for the menu item.
<p>However, if your action provider provides a submenu, through the {@link
-android.view.ActionProvider#onPrepareSubMenu onPrepareSubMenu()} callback, then the submenu
-appears even when the menu item is in the overflow menu. Thus, {@link
-android.view.ActionProvider#onPerformDefaultAction()} is never called when there is a
+android.support.v4.view.ActionProvider#onPrepareSubMenu onPrepareSubMenu()} callback, then the
+submenu appears even when the action provider is placed in the action overflow. Thus, {@link
+android.support.v4.view.ActionProvider#onPerformDefaultAction()} is never called when there is a
submenu.</p>
+
<p class="note"><strong>Note:</strong> An activity or a fragment that implements {@link
android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} can override the action
-provider's default behavior by handling the item-selected event (and returning true), in which
-case, the system does not call {@link android.view.ActionProvider#onPerformDefaultAction()}.</p>
+provider's default behavior (unless it uses a submenu) by handling the item-selected event (and
+returning <code>true</code>), in which case, the system does not call {@link
+android.support.v4.view.ActionProvider#onPerformDefaultAction()}.</p>
+
</dd>
</dl>
@@ -927,62 +873,68 @@
<h2 id="Tabs">Adding Navigation Tabs</h2>
+<img src="{@docRoot}images/ui/actionbar-tabs@2x.png" width="760" alt="" />
+<p class="img-caption"><strong>Figure 7.</strong> Action bar tabs on a wide screen.</p>
-<div class="figure" style="width:450px">
- <img src="{@docRoot}images/ui/actionbar.png" alt="" />
- <p class="img-caption"><strong>Figure 9.</strong> Screenshot of action bar tabs from the <a
-href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app.</p>
+<a class="notice-designers" href="{@docRoot}design/building-blocks/tabs.html">
+ <div>
+ <h3>Design Guide</h3>
+ <p>Tabs</p>
+ </div>
+</a>
+
+<a class="notice-developers" href="{@docRoot}training/implementing-navigation/lateral.html">
+ <div>
+ <h3>Also read</h3>
+ <p>Creating Swipe Views with Tabs</p>
+ </div>
+</a>
+
+
+<div class="figure" style="width:240px">
+ <img src="{@docRoot}images/ui/actionbar-tabs-stacked@2x.png" width="240" alt="" />
+ <p class="img-caption"><strong>Figure 8.</strong> Tabs on a narrow screen.</p>
</div>
-<div class="figure" style="width:250px">
- <img src="{@docRoot}images/ui/actionbar-stacked.png" alt="" />
- <p class="img-caption"><strong>Figure 10.</strong> Screenshot of tabs in the stacked action
-bar on a narrow screen.</p>
-</div>
+<p>Tabs in the action bar make it easy for users to explore and switch between different views in
+your app. The tabs provided by the {@link android.support.v7.app.ActionBar} are ideal because they
+adapt to different screen sizes. For example, when the screen is wide enough the tabs appear in the
+action bar alongside the action buttons (such as when on a tablet, shown in figure 7), while when
+on a narrow screen they appear in a separate bar (known as the "stacked action bar", shown in
+figure 8). In some cases, the Android system will instead show your tab items as a drop-down list
+to ensure the best fit in the action bar.</p>
-<p>When you want to provide navigation tabs in an activity, using the action bar's
-tabs is a great option (instead of using {@link android.widget.TabWidget}), because the
-system adapts the action bar tabs for different screen sizes—placing them in the main action
-bar when the screen is sufficiently wide, or in a separate bar (known as the "stacked action bar")
-when the screen is too narrow, as shown in figures 9 and 10.</p>
+<p>To get started, your layout must include a {@link android.view.ViewGroup} in which you place
+each {@link android.app.Fragment} associated with a tab. Be sure the {@link android.view.ViewGroup}
+has a resource ID so you can reference it from your code and swap the tabs within it.
+Alternatively, if the tab content will fill the activity layout, then your activity doesn't need a
+layout at all (you don't even need to call {@link android.app.Activity#setContentView
+setContentView()}). Instead, you can place each fragment in the default root view, which you can
+refer to with the {@code android.R.id.content} ID.</p>
-<p>To switch between fragments using the tabs, you must perform a fragment
-transaction each time a tab is selected. If you're not familiar with how to change fragments
-using {@link android.app.FragmentTransaction}, first read the <a
-href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
-
-<p>To get started, your layout must include a {@link android.view.ViewGroup} in which you place each
-{@link android.app.Fragment} associated with a tab. Be sure the {@link android.view.ViewGroup} has a
-resource ID so you can reference it from your tab-swapping code. Alternatively, if the tab content
-will fill the activity layout (excluding the action bar), then your activity doesn't need a layout
-at all (you don't even need to call {@link android.app.Activity#setContentView
-setContentView()}). Instead, you can place each fragment in the default root {@link
-android.view.ViewGroup}, which you can refer to with the {@code android.R.id.content} ID (you can
-see this ID used in the sample code below, during fragment transactions).</p>
<p>Once you determine where the fragments appear in the layout, the basic procedure to add tabs
is:</p>
<ol>
- <li>Implement the {@link android.app.ActionBar.TabListener} interface. Callbacks in this
-interface respond to user events on the tabs so you can swap fragments.</li>
- <li>For each tab you want to add, instantiate an {@link android.app.ActionBar.Tab} and set the
-{@link android.app.ActionBar.TabListener} by calling {@link android.app.ActionBar.Tab#setTabListener
-setTabListener()}. Also set the tab's title and/or icon with {@link
-android.app.ActionBar.Tab#setText setText()} and/or {@link android.app.ActionBar.Tab#setIcon
-setIcon()}.</li>
- <li>Add each tab to the action bar by calling {@link android.app.ActionBar#addTab addTab()}.</li>
+ <li>Implement the {@link android.support.v7.app.ActionBar.TabListener} interface. This interface
+ provides callbacks for tab events, such as when the user presses one so you can swap the
+ tabs.</li>
+ <li>For each tab you want to add, instantiate an {@link android.support.v7.app.ActionBar.Tab}
+ and set the {@link android.support.v7.app.ActionBar.TabListener} by calling {@link
+ android.support.v7.app.ActionBar.Tab#setTabListener setTabListener()}. Also set the tab's title
+ and with {@link android.app.ActionBar.Tab#setText setText()} (and optionally, an icon with
+ {@link android.app.ActionBar.Tab#setIcon setIcon()}).</li>
+ <li>Then add each tab to the action bar by calling {@link android.support.v7.app.ActionBar#addTab
+ addTab()}.</li>
</ol>
-<p>When looking at the {@link android.app.ActionBar.TabListener} interface, notice that the
-callback methods provide only the {@link android.app.ActionBar.Tab} that was selected and a {@link
-android.app.FragmentTransaction} for you to perform fragment transactions—it doesn't say
-anything about what fragment you should swap in or out. Thus, you must define your own association
+<p>Notice that the {@link android.support.v7.app.ActionBar.TabListener}
+callback methods don't specify which fragment is associated with the tab, but merely which
+{@link android.support.v7.app.ActionBar.Tab} was selected.
+You must define your own association
between each {@link android.app.ActionBar.Tab} and the appropriate {@link android.app.Fragment} that
-it represents (in order to perform the appropriate fragment transaction). There are several ways you
-can define the association, depending on your design. In the example below, the {@link
-android.app.ActionBar.TabListener} implementation provides a constructor such that each new tab uses
-its own instance of the listener. Each instance of the listener defines several fields that are
-necessary to later perform a transaction on the appropriate fragment.</p>
+it represents. There are several ways you
+can define the association, depending on your design.</p>
<p>For example, here's how you might implement the {@link android.app.ActionBar.TabListener}
such that each tab uses its own instance of the listener:</p>
@@ -1042,13 +994,10 @@
android.R.id.content} view group)—when the respective tab is selected, and detaches ({@link
android.app.FragmentTransaction#detach detach()}) it when the tab is unselected.</p>
-<p>The {@link android.app.ActionBar.TabListener} implementation is the bulk of the work. All that
-remains is to create each {@link android.app.ActionBar.Tab} and add it to the {@link
+<p>All that remains is to create each {@link android.app.ActionBar.Tab} and add it to the {@link
android.app.ActionBar}. Additionally, you must call {@link
android.app.ActionBar#setNavigationMode(int) setNavigationMode(NAVIGATION_MODE_TABS)} to make the
-tabs visible. You might also want to disable the activity title by calling {@link
-android.app.ActionBar#setDisplayShowTitleEnabled setDisplayShowTitleEnabled(false)} if the tab
-titles actually indicate the current view.</p>
+tabs visible.</p>
<p>For example, the following code adds two tabs using the listener defined above:</p>
@@ -1060,62 +1009,70 @@
// android.R.id.content as the container for each fragment
// setup action bar for tabs
- ActionBar actionBar = getActionBar();
+ ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
Tab tab = actionBar.newTab()
- .setText(R.string.artist)
- .setTabListener(new TabListener<ArtistFragment>(
- this, "artist", ArtistFragment.class));
+ .setText(R.string.artist)
+ .setTabListener(new TabListener<ArtistFragment>(
+ this, "artist", ArtistFragment.class));
actionBar.addTab(tab);
tab = actionBar.newTab()
- .setText(R.string.album)
- .setTabListener(new TabListener<AlbumFragment>(
- this, "album", AlbumFragment.class));
+ .setText(R.string.album)
+ .setTabListener(new TabListener<AlbumFragment>(
+ this, "album", AlbumFragment.class));
actionBar.addTab(tab);
}
</pre>
-<p class="note"><strong>Note:</strong> The above implementation for {@link
-android.app.ActionBar.TabListener} is one of several possible techniques. You can see more of
-this style in the <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.html"
->API Demos</a> app.</p>
+<p>If your activity stops, you should retain the currently selected tab with the <a href=
+"{@docRoot}guide/components/activities.html#SavingActivityState">saved instance state</a> so you
+can open the appropriate tab when the user returns. When it's time to save the state, you can query
+the currently selected tab with {@link
+android.support.v7.app.ActionBar#getSelectedNavigationIndex()}. This returns the index position of
+the selected tab.</p>
-<p>If your activity stops, you should retain the currently selected tab with the <a
-href="{@docRoot}guide/components/activities.html#SavingActivityState">saved instance
-state</a> so you can open the appropriate tab when the user returns. When it's time to save the
-state, you can query the currently selected tab with {@link
-android.app.ActionBar#getSelectedNavigationIndex()}. This returns the index position of the selected
-tab.</p>
<p class="caution"><strong>Caution:</strong> It's important that you save the state of each fragment
-as necessary, so that when users switch fragments with the tabs and then return to a previous
-fragment, it looks the way it did when they left. For information about saving the state of your
+so when users switch fragments with the tabs and then return to a previous
+fragment, it looks the way it did when they left. Some of the state is saved by default, but you
+may need to manually save state for customized views. For information about saving the state of your
fragment, see the <a href="{@docRoot}guide/components/fragments.html">Fragments</a>
-developer guide.</p>
+API guide.</p>
+
+<p class="note"><strong>Note:</strong> The above implementation for {@link
+android.support.v7.app.ActionBar.TabListener} is one of several possible techniques. Another popular
+option is to use {@link android.support.v4.view.ViewPager} to manage the fragments so users
+can also use a swipe gesture to switch tabs. In this case, you simply tell the
+{@link android.support.v4.view.ViewPager} the current tab position in the
+{@link android.support.v7.app.ActionBar.TabListener#onTabSelected onTabSelected()} callback.
+For more information, read
+<a href="{@docRoot}training/implementing-navigation/lateral.html"
+>Creating Swipe Views with Tabs</a>.</p>
-<p class="note"><strong>Note:</strong> In some cases, the Android system will show your action
-bar tabs as a drop-down list in order to ensure the best fit in the action bar.</p>
+
<h2 id="Dropdown">Adding Drop-down Navigation</h2>
-<p>As another mode of navigation (or filtering) within your activity, the action bar offers a
-built in drop-down list. For example, the drop-down list can offer different modes by which content
-in the activity is sorted.</p>
-
-<!--
-<div class="figure" style="width:135px">
- <img src="{@docRoot}images/ui/actionbar-dropdown.png" alt="" />
- <p class="img-caption"><strong>Figure 5.</strong> Screenshot of a drop-down navigation list in the
+<div class="figure" style="width:240px">
+ <img src="{@docRoot}images/ui/actionbar-dropdown@2x.png" alt="" width="240" />
+ <p class="img-caption"><strong>Figure 9.</strong> A drop-down navigation list in the
action bar.</p>
</div>
--->
+
+<p>As another mode of navigation (or filtering) for your activity, the action bar offers a built
+in drop-down list (also known as a "spinner"). For example, the drop-down list can offer different
+modes by which content in the activity is sorted.</p>
+
+<p>Using the drop-down list is useful when changing the content is important but not necessarily a
+frequent occurrence. In cases where switching the content is more frequent,
+you should use <a href="#Tabs">navigation tabs</a> instead.</p>
+
<p>The basic procedure to enable drop-down navigation is:</p>
@@ -1123,36 +1080,31 @@
<li>Create a {@link android.widget.SpinnerAdapter} that provides the
list of selectable items for the drop-down and the layout to use when drawing each item in the
list.</li>
- <li>Implement {@link android.app.ActionBar.OnNavigationListener} to define the behavior that
-occurs when the user selects an item from the list.</li>
- <li>Enable navigation mode for the action bar with {@link
-android.app.ActionBar#setNavigationMode setNavigationMode()}. For example:
-<pre>
-ActionBar actionBar = getActionBar();
-actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
-</pre>
- <p class="note"><strong>Note:</strong> You should perform this during your activity's {@link
-android.app.Activity#onCreate
-onCreate()} method.</p>
+ <li>Implement {@link android.support.v7.app.ActionBar.OnNavigationListener} to define the
+ behavior that occurs when the user selects an item from the list.</li>
+ <li>During your activity's {@link android.app.Activity#onCreate
+onCreate()} method, enable the action bar's drop-down list by calling {@link
+android.support.v7.app.ActionBar#setNavigationMode setNavigationMode(NAVIGATION_MODE_LIST)}.
</li>
<li>Set the callback for the drop-down list with {@link
-android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}. For example:
+android.support.v7.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}.
+For example:
<pre>
actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);
</pre>
<p>This method takes your {@link android.widget.SpinnerAdapter} and {@link
-android.app.ActionBar.OnNavigationListener}.</p>
+android.support.v7.app.ActionBar.OnNavigationListener}.</p>
</li>
</ol>
-<p>That's the basic setup. However, implementing the {@link android.widget.SpinnerAdapter} and
-{@link android.app.ActionBar.OnNavigationListener} is where most of the work is done. There are many
-ways you can implement these to define the functionality for your drop-down navigation and
+<p>This procedure is relatively short, but implementing the {@link android.widget.SpinnerAdapter}
+and {@link android.app.ActionBar.OnNavigationListener} is where most of the work is done. There are
+many ways you can implement these to define the functionality for your drop-down navigation and
implementing various types of {@link android.widget.SpinnerAdapter} is beyond the scope of this
document (you should refer to the {@link android.widget.SpinnerAdapter} class reference for more
-information). However, below is a simple example for a {@link android.widget.SpinnerAdapter} and
-{@link android.app.ActionBar.OnNavigationListener} to get you started (click the title to
-reveal the sample).</p>
+information). However, below is an example for a {@link android.widget.SpinnerAdapter} and {@link
+android.app.ActionBar.OnNavigationListener} to get you started (click the title to reveal the
+sample).</p>
@@ -1283,31 +1235,71 @@
+
+
<h2 id="Style">Styling the Action Bar</h2>
-<p>If you've implemented a custom design for the widgets in your application, you might
-also want to redesign some of the action bar to match your app design. To do so, you need to use
-Android's <a
-href="{@docRoot}guide/topics/ui/themes.html">style and theme</a> framework to restyle the action
-bar using special style properties.</p>
+<p>If you want to implement a visual design that represents your app's brand, the action bar allows
+you to customize each detail of its appearance, including the action bar color, text colors, button
+styles, and more. To do so, you need to use Android's <a href=
+"{@docRoot}guide/topics/ui/themes.html">style and theme</a> framework to restyle the action bar
+using special style properties.</p>
+<p class="caution"><strong>Caution:</strong> For all background drawables you provide, be sure to
+use <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">Nine-Patch drawables</a>
+to allow stretching. The nine-patch image should be <em>smaller</em> than 40dp tall and 30dp
+wide.</p>
-<p class="note"><strong>Note:</strong> In order for background images to change appearance
-depending on the current button state (selected, pressed, unselected), the drawable resource you use
-must be a <a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">state
-list drawable</a>.</p>
-
-<p class="caution"><strong>Caution:</strong> For all background drawables you provide, be sure to use <a
-href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">Nine-Patch drawables</a> to allow
-stretching. The Nine-Patch image should be <em>smaller</em> than 40px tall and 30px wide (for the mdpi asset).</p>
<h3 id="GeneralStyles">General appearance</h3>
<dl>
+ <dt>{@link android.R.attr#actionBarStyle
+ actionBarStyle}</dt>
+ <dd>Specifies a style resource that defines various style properties
+ for the action bar.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_ActionBar
+ Widget.AppCompat.ActionBar}, which is what you should use as the parent style.</p>
+ <p>Supported styles include:</p>
+ <dl>
+ <dt>{@link android.R.attr#background}</dt>
+ <dd>Defines a drawable resource for the action bar background.</dd>
+ <dt>{@link android.R.attr#backgroundStacked}</dt>
+ <dd>Defines a drawable resource for the stacked action bar
+ (the <a href="#Tabs">tabs</a>).</dd>
+ <dt>{@link android.R.attr#backgroundSplit}</dt>
+ <dd>Defines a drawable resource for the <a href="#SplitBar">split action bar</a>.</dd>
+ <dt>{@link android.R.attr#actionButtonStyle}</dt>
+ <dd>Defines a style resource for action buttons.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_ActionButton
+ Widget.AppCompat.ActionButton}, which is what you should use as the parent style.</p>
+ </dd>
+ <dt>{@link android.R.attr#actionOverflowButtonStyle}</dt>
+ <dd>Defines a style resource for overflow action items.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_ActionButton_Overflow
+ Widget.AppCompat.ActionButton.Overflow}, which is what you should use as the parent style.</p>
+ </dd>
+ <dt>{@link android.R.attr#displayOptions}</dt>
+ <dd>Defines one or more action bar display options, such as whether to use the app logo,
+ show the activity title, or enable the <em>Up</em> action. See {@link
+ android.R.attr#displayOptions} for all possible values.
+ <dt>{@link android.R.attr#divider}</dt>
+ <dd>Defines a drawable resource for the divider between action items.</dd>
+ <dt>{@link android.R.attr#titleTextStyle}</dt>
+ <dd>Defines a style resource for the action bar title.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#TextAppearance_AppCompat_Widget_ActionBar_Title
+ TextAppearance.AppCompat.Widget.ActionBar.Title}, which is what you should use as the parent
+ style.</p></dd>
+ </dl>
+ </dd>
<dt>{@link android.R.attr#windowActionBarOverlay
- android:windowActionBarOverlay}</dt>
+ windowActionBarOverlay}</dt>
<dd>Declares whether the action bar should overlay the activity layout rather than offset the
activity's layout position (for example, the Gallery app uses overlay mode). This is
{@code false} by default.
@@ -1322,9 +1314,9 @@
draw the action bar with a semi-transparent background by default. However, you can modify it with
your own styles and the {@link android.R.style#Theme_DeviceDefault DeviceDefault} theme on
different devices might use an opaque background by default.</p>
- <p>When overlay mode is enabled, your activity layout has no awareness of the action bar laying on
+ <p>When overlay mode is enabled, your activity layout has no awareness of the action bar lying on
top of it. So, you must be careful not to place any important information or UI components in the
-area overlayed by the action bar. If appropriate, you can refer to the platform's value for {@link
+area overlaid by the action bar. If appropriate, you can refer to the platform's value for {@link
android.R.attr#actionBarSize} to determine the height of the action bar, by referencing it
in your XML layout. For example:</p>
<pre>
@@ -1334,13 +1326,13 @@
</pre>
<p>You can also retrieve the action bar height at runtime with {@link
android.app.ActionBar#getHeight()}. This reflects the height of the action bar at the time it's
-called, which might not include the stacked action bar (due to navigation tabs) if called during early
-activity lifecycle methods. To see how you can determine the total height at runtime, including the
-stacked action bar, see the <a
-href="{@docRoot}resources/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.html"
->{@code TitlesFragment}</a> class in the <a
-href="{@docRoot}resources/samples/HoneycombGallery/index.html"
->Honeycomb Gallery</a> sample app.</p>
+called, which might not include the stacked action bar (due to navigation tabs) if called during
+early activity lifecycle methods. To see how you can determine the total height at runtime,
+including the stacked action bar, see the <a href=
+"{@docRoot}resources/samples/HoneycombGallery/src/com/example/android/hcgallery/TitlesFragment.html">
+{@code TitlesFragment}</a> class in the <a href=
+"{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> sample app.</p>
+
</dd>
</dl>
@@ -1350,34 +1342,40 @@
<dl>
<dt>{@link android.R.attr#actionButtonStyle
- android:actionButtonStyle}</dt>
- <dd>Defines a style resource for the action item buttons.</dd>
+ actionButtonStyle}</dt>
+ <dd>Defines a style resource for the action item buttons.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_ActionButton
+ Widget.AppCompat.ActionButton}, which is what you should use as the parent style.</p></dd>
<dt>{@link android.R.attr#actionBarItemBackground
- android:actionBarItemBackground}</dt>
- <dd>Defines a drawable resource for each action item's background. (Added in API level 14.)</dd>
+ actionBarItemBackground}</dt>
+ <dd>Defines a drawable resource for each action item's background.
+ This should be a <a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList"
+ >state-list drawable</a> to indicate different selected states.</dd>
<dt>{@link android.R.attr#itemBackground
- android:itemBackground}</dt>
- <dd>Defines a drawable resource for each overflow menu item's background.</dd>
+ itemBackground}</dt>
+ <dd>Defines a drawable resource for each action overflow item's background.
+ This should be a <a href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList"
+ >state-list drawable</a> to indicate different selected states.</dd>
<dt>{@link android.R.attr#actionBarDivider
- android:actionBarDivider}</dt>
- <dd>Defines a drawable resource for the divider between action items. (Added in API level
-14.)</dd>
+ actionBarDivider}</dt>
+ <dd>Defines a drawable resource for the divider between action items.</dd>
<dt>{@link android.R.attr#actionMenuTextColor
- android:actionMenuTextColor}</dt>
+ actionMenuTextColor}</dt>
<dd>Defines a color for text that appears in an action item.</dd>
<dt>{@link android.R.attr#actionMenuTextAppearance
- android:actionMenuTextAppearance}</dt>
+ actionMenuTextAppearance}</dt>
<dd>Defines a style resource for text that appears in an action item.</dd>
<dt>{@link android.R.attr#actionBarWidgetTheme
- android:actionBarWidgetTheme}</dt>
+ actionBarWidgetTheme}</dt>
<dd>Defines a theme resource for widgets that are inflated into the action bar as <a
-href="#ActionView">action views</a>. (Added in API level 14.)</dd>
+href="#ActionView">action views</a>.</dd>
</dl>
@@ -1385,16 +1383,25 @@
<dl>
<dt>{@link android.R.attr#actionBarTabStyle
- android:actionBarTabStyle}</dt>
- <dd>Defines a style resource for tabs in the action bar.</dd>
+ actionBarTabStyle}</dt>
+ <dd>Defines a style resource for tabs in the action bar.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_ActionBar_TabView
+ Widget.AppCompat.ActionBar.TabView}, which is what you should use as the parent style.</p></dd>
<dt>{@link android.R.attr#actionBarTabBarStyle
- android:actionBarTabBarStyle}</dt>
- <dd>Defines a style resource for the thin bar that appears below the navigation tabs.</dd>
+ actionBarTabBarStyle}</dt>
+ <dd>Defines a style resource for the thin bar that appears below the navigation tabs.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_ActionBar_TabBar
+ Widget.AppCompat.ActionBar.TabBar}, which is what you should use as the parent style.</p></dd>
<dt>{@link android.R.attr#actionBarTabTextStyle
- android:actionBarTabTextStyle}</dt>
- <dd>Defines a style resource for text in the navigation tabs.</dd>
+ actionBarTabTextStyle}</dt>
+ <dd>Defines a style resource for text in the navigation tabs.
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_ActionBar_TabText
+ Widget.AppCompat.ActionBar.TabText}, which is what you should use as the parent style.</p></dd>
</dl>
@@ -1402,82 +1409,93 @@
<dl>
<dt>{@link android.R.attr#actionDropDownStyle
- android:actionDropDownStyle}</dt>
- <dd>Defines a style for the drop-down navigation (such as the background and text styles).</dd>
+ actionDropDownStyle}</dt>
+ <dd>Defines a style for the drop-down navigation (such as the background and text styles).
+ <p>The default for this style for this
+ is {@link android.support.v7.appcompat.R.style#Widget_AppCompat_Spinner_DropDown_ActionBar
+ Widget.AppCompat.Spinner.DropDown.ActionBar}, which is what you should use as the parent
+ style.</p></dd>
</dl>
+<h3 id="StyleExample">Example theme</h3>
-<p>For example, here's a file that defines a few custom styles for the action bar:</p>
+<p>Here's an example that defines a custom theme for an activity, {@code CustomActivityTheme},
+that includes several styles to customize the action bar.</p>
+
+<p>Notice that there are two version for each action bar style property. The first one
+includes the {@code android:} prefix on the property name to support API levels 11 and higher
+that include these properties in the framework. The second version does <em>not</em>
+include the {@code android:} prefix and is for older versions of the platform, on which
+the system uses the style property from the support library. The effect for each is the same.</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- the theme applied to the application or activity -->
- <style name="CustomActivityTheme" parent="@android:style/Theme.Holo">
- <item name="android:actionBarTabTextStyle">@style/CustomTabTextStyle</item>
- <item name="android:actionBarDivider">@drawable/ab_divider</item>
- <item name="android:actionBarItemBackground">@drawable/ab_item_background</item>
+ <style name="CustomActionBarTheme"
+ parent="@style/Theme.AppCompat.Light">
+ <item name="android:actionBarStyle">@style/MyActionBar</item>
+ <item name="android:actionBarTabTextStyle">@style/TabTextStyle</item>
+ <item name="android:actionMenuTextColor">@color/actionbar_text</item>
+
+ <!-- Support library compatibility -->
+ <item name="actionBarStyle">@style/MyActionBar</item>
+ <item name="actionBarTabTextStyle">@style/TabTextStyle</item>
+ <item name="actionMenuTextColor">@color/actionbar_text</item>
</style>
- <!-- style for the action bar tab text -->
- <style name="CustomTabTextStyle" parent="@android:style/TextAppearance.Holo">
- <item name="android:textColor">#2456c2</item>
+ <!-- general styles for the action bar -->
+ <style name="MyActionBar"
+ parent="@style/Widget.AppCompat.ActionBar">
+ <item name="android:titleTextStyle">@style/TitleTextStyle</item>
+ <item name="android:background">@drawable/actionbar_background</item>
+ <item name="android:backgroundStacked">@drawable/actionbar_background</item>
+ <item name="android:backgroundSplit">@drawable/actionbar_background</item>
+
+ <!-- Support library compatibility -->
+ <item name="titleTextStyle">@style/TitleTextStyle</item>
+ <item name="background">@drawable/actionbar_background</item>
+ <item name="backgroundStacked">@drawable/actionbar_background</item>
+ <item name="backgroundSplit">@drawable/actionbar_background</item>
+ </style>
+
+ <!-- action bar title text -->
+ <style name="TitleTextStyle"
+ parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">
+ <item name="android:textColor">@color/actionbar_text</item>
+ </style>
+
+ <!-- action bar tab text -->
+ <style name="TabTextStyle"
+ parent="@style/Widget.AppCompat.ActionBar.TabText">
+ <item name="android:textColor">@color/actionbar_text</item>
</style>
</resources>
+
</pre>
-<p class="note"><strong>Note:</strong> Be certain that your theme declares a parent theme in the
-{@code <style>} tag, from which it inherits all styles not explicitly declared by your theme.
-When modifying the action bar, using a parent theme is important so that you can simply override the
-action bar styles you want to change without re-implementing the styles you want to leave alone
-(such as text appearance or padding in action items).</p>
-
-<p>You can apply your custom theme to the entire application or to individual activities in your
-manifest file like this:</p>
+<p>In your manifest file, you can apply the theme to your entire app:</p>
<pre>
-<application android:theme="@style/CustomActivityTheme" ... />
+<application android:theme="@style/CustomActionBarTheme" ... />
</pre>
+<p>Or to individual activities:</p>
+
+<pre>
+<activity android:theme="@style/CustomActionBarTheme" ... />
+</pre>
+
+
+<p class="caution"><strong>Caution:</strong> Be certain that each theme and style declares a parent
+theme in the {@code <style>} tag, from which it inherits all styles not explicitly declared
+by your theme. When modifying the action bar, using a parent theme is important so that you can
+simply override the action bar styles you want to change without re-implementing the styles you
+want to leave alone (such as text size or padding in action items).</p>
+
<p>For more information about using style and theme resources in your application, read <a
href="{@docRoot}guide/topics/ui/themes.html">Styles and Themes</a>.</p>
-<h3 id="AdvancedStyles">Advanced styling</h3>
-
- <p>If you need more advanced styling for the action bar than is available with the
-properties above, you can include {@link android.R.attr#actionBarStyle android:actionBarStyle} and
-{@link android.R.attr#actionBarSplitStyle android:actionBarSplitStyle} in your activity's theme.
-Each of these specifies another style that can define various properties for the action bar,
-including different backgrounds with {@link android.R.attr#background android:background}, {@link
-android.R.attr#backgroundSplit android:backgroundSplit}, and {@link android.R.attr#backgroundStacked
-android:backgroundStacked}. If you override these action bar styles, be sure that you define a
-parent action bar style such as {@link android.R.style#Widget_Holo_ActionBar
-Widget.Holo.ActionBar}.</p>
-
-<p>For example, if you want to change the action bar's background, you can use the following
-styles:</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- the theme applied to the application or activity -->
- <style name="CustomActivityTheme" parent="@android:style/Theme.Holo">
- <item name="android:actionBarStyle">@style/MyActionBar</item>
- <!-- other activity and action bar styles here -->
- </style>
-
- <!-- style for the action bar backgrounds -->
- <style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">
- <item name="android:background">@drawable/ab_background</item>
- <item name="android:backgroundStacked">@drawable/ab_background</item>
- <item name="android:backgroundSplit">@drawable/ab_split_background</item>
- </style>
-</resources>
-</pre>
-
-
-
-
diff --git a/docs/html/guide/topics/ui/controls/pickers.jd b/docs/html/guide/topics/ui/controls/pickers.jd
index a0e7afb..4c55840 100644
--- a/docs/html/guide/topics/ui/controls/pickers.jd
+++ b/docs/html/guide/topics/ui/controls/pickers.jd
@@ -47,11 +47,11 @@
<p>Although {@link android.app.DialogFragment} was first added to the platform in Android 3.0 (API
level 11), if your app supports versions of Android older than 3.0—even as low as Android
1.6—you can use the {@link android.support.v4.app.DialogFragment} class that's available in
-the <a href="{@docRoot}tools/extras/support-library.html">support library</a> for backward
+the <a href="{@docRoot}tools/support-library/index.html">support library</a> for backward
compatibility.</p>
<p class="note"><strong>Note:</strong> The code samples below show how to create dialogs for a time
-picker and date picker using the <a href="{@docRoot}tools/extras/support-library.html">support
+picker and date picker using the <a href="{@docRoot}tools/support-library/index.html">support
library</a> APIs for {@link android.support.v4.app.DialogFragment}. If your app's <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> is 11 or
higher, you can instead use the platform version of {@link android.app.DialogFragment}.</p>
@@ -67,7 +67,7 @@
<p class="note"><strong>Note:</strong> If your app supports versions of Android older than 3.0,
be sure you've set up your Android project with the support library as described in <a
-href="{@docRoot}tools/extras/support-library.html#SettingUp">Setting Up a Project to Use a
+href="{@docRoot}tools/support-library/setup.html">Setting Up a Project to Use a
Library</a>.</p>
<h3 id="TimePickerFragment">Extending DialogFragment for a time picker</h3>
@@ -172,7 +172,7 @@
<p class="note"><strong>Note:</strong> If your app supports versions of Android older than 3.0,
be sure you've set up your Android project with the support library as described in <a
-href="{@docRoot}tools/extras/support-library.html#SettingUp">Setting Up a Project to Use a
+href="{@docRoot}tools/support-library/setup.html">Setting Up a Project to Use a
Library</a>.</p>
<h3 id="DatePickerFragment">Extending DialogFragment for a date picker</h3>
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index 7f48eac..09767bf 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -97,7 +97,7 @@
Because the {@link android.app.DialogFragment} class was originally added with
Android 3.0 (API level 11), this document describes how to use the {@link
android.support.v4.app.DialogFragment} class that's provided with the <a
-href="{@docRoot}tools/extras/support-library.html">Support Library</a>. By adding this library
+href="{@docRoot}tools/support-library/index.html">Support Library</a>. By adding this library
to your app, you can use {@link android.support.v4.app.DialogFragment} and a variety of other
APIs on devices running Android 1.6 or higher. If the minimum version your app supports
is API level 11 or higher, then you can use the framework version of {@link
diff --git a/docs/html/guide/topics/ui/layout/listview.jd b/docs/html/guide/topics/ui/layout/listview.jd
index 6cdd725..f8315c5 100644
--- a/docs/html/guide/topics/ui/layout/listview.jd
+++ b/docs/html/guide/topics/ui/layout/listview.jd
@@ -48,7 +48,7 @@
<p>Although the {@link android.support.v4.content.CursorLoader} APIs were first introduced in
Android 3.0 (API level 11), they are also available in the <a
-href="{@docRoot}tools/extras/support-library.html">Support Library</a> so that your app may use them
+href="{@docRoot}tools/support-library/index.html">Support Library</a> so that your app may use them
while supporting devices running Android 1.6 or higher.</p>
<p>For more information about using a {@link
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 05ec279..e0c87d7 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -94,7 +94,7 @@
<p class="note">
<strong>Note:</strong> Except where noted, this guide refers to the
{@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} class
- in the version 4 <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.
+ in the version 4 <a href="{@docRoot}tools/support-library/index.html">Support Library</a>.
The class {@link android.app.Notification.Builder Notification.Builder} was added in Android
3.0.
</p>
diff --git a/docs/html/images/jb-android-43.jpg b/docs/html/images/jb-android-43.jpg
new file mode 100644
index 0000000..8dc5c2d
--- /dev/null
+++ b/docs/html/images/jb-android-43.jpg
Binary files differ
diff --git a/docs/html/images/jb-android-43@2x.png b/docs/html/images/jb-android-43@2x.png
new file mode 100644
index 0000000..385c0ff
--- /dev/null
+++ b/docs/html/images/jb-android-43@2x.png
Binary files differ
diff --git a/docs/html/images/jb-btle.png b/docs/html/images/jb-btle.png
new file mode 100644
index 0000000..7fb367a
--- /dev/null
+++ b/docs/html/images/jb-btle.png
Binary files differ
diff --git a/docs/html/images/jb-gpu-profile-cal-n4.png b/docs/html/images/jb-gpu-profile-cal-n4.png
new file mode 100644
index 0000000..97adaaa
--- /dev/null
+++ b/docs/html/images/jb-gpu-profile-cal-n4.png
Binary files differ
diff --git a/docs/html/images/jb-gpu-profile-clk-n4.png b/docs/html/images/jb-gpu-profile-clk-n4.png
new file mode 100644
index 0000000..72c0a40
--- /dev/null
+++ b/docs/html/images/jb-gpu-profile-clk-n4.png
Binary files differ
diff --git a/docs/html/images/jb-profiles-create-n713.png b/docs/html/images/jb-profiles-create-n713.png
new file mode 100644
index 0000000..f5e9038
--- /dev/null
+++ b/docs/html/images/jb-profiles-create-n713.png
Binary files differ
diff --git a/docs/html/images/jb-profiles-restrictions-n713.png b/docs/html/images/jb-profiles-restrictions-n713.png
new file mode 100644
index 0000000..4600860
--- /dev/null
+++ b/docs/html/images/jb-profiles-restrictions-n713.png
Binary files differ
diff --git a/docs/html/images/jb-pseudo-locale-zz.png b/docs/html/images/jb-pseudo-locale-zz.png
new file mode 100644
index 0000000..84b3383
--- /dev/null
+++ b/docs/html/images/jb-pseudo-locale-zz.png
Binary files differ
diff --git a/docs/html/images/jb-rtl-arabic-n4.png b/docs/html/images/jb-rtl-arabic-n4.png
new file mode 100644
index 0000000..f62a987
--- /dev/null
+++ b/docs/html/images/jb-rtl-arabic-n4.png
Binary files differ
diff --git a/docs/html/images/jb-rtl-hebrew-n4.png b/docs/html/images/jb-rtl-hebrew-n4.png
new file mode 100644
index 0000000..bc7e630
--- /dev/null
+++ b/docs/html/images/jb-rtl-hebrew-n4.png
Binary files differ
diff --git a/docs/html/images/jb-systrace.png b/docs/html/images/jb-systrace.png
new file mode 100644
index 0000000..9d76ad4
--- /dev/null
+++ b/docs/html/images/jb-systrace.png
Binary files differ
diff --git a/docs/html/images/practices/actionbar-phone-splitaction.png b/docs/html/images/practices/actionbar-phone-splitaction.png
index a0081e7..24f93f6 100644
--- a/docs/html/images/practices/actionbar-phone-splitaction.png
+++ b/docs/html/images/practices/actionbar-phone-splitaction.png
Binary files differ
diff --git a/docs/html/images/practices/actionbar-phone-splitaction@2x.png b/docs/html/images/practices/actionbar-phone-splitaction@2x.png
new file mode 100644
index 0000000..3fe577c
--- /dev/null
+++ b/docs/html/images/practices/actionbar-phone-splitaction@2x.png
Binary files differ
diff --git a/docs/html/images/tools/sdk-manager-support-libs.png b/docs/html/images/tools/sdk-manager-support-libs.png
new file mode 100644
index 0000000..3796800
--- /dev/null
+++ b/docs/html/images/tools/sdk-manager-support-libs.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-dropdown.png b/docs/html/images/ui/actionbar-dropdown.png
new file mode 100644
index 0000000..26d171d
--- /dev/null
+++ b/docs/html/images/ui/actionbar-dropdown.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-dropdown@2x.png b/docs/html/images/ui/actionbar-dropdown@2x.png
new file mode 100644
index 0000000..07fd2ac
--- /dev/null
+++ b/docs/html/images/ui/actionbar-dropdown@2x.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-item-withtext.png b/docs/html/images/ui/actionbar-item-withtext.png
index 5f7aecc..8d217b1 100644
--- a/docs/html/images/ui/actionbar-item-withtext.png
+++ b/docs/html/images/ui/actionbar-item-withtext.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-searchview.png b/docs/html/images/ui/actionbar-searchview.png
index 7ae46a0..bd1c1e1 100644
--- a/docs/html/images/ui/actionbar-searchview.png
+++ b/docs/html/images/ui/actionbar-searchview.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-searchview@2x.png b/docs/html/images/ui/actionbar-searchview@2x.png
new file mode 100644
index 0000000..e14ba8b
--- /dev/null
+++ b/docs/html/images/ui/actionbar-searchview@2x.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-shareaction.png b/docs/html/images/ui/actionbar-shareaction.png
index fdbb02c..6f489d9 100644
--- a/docs/html/images/ui/actionbar-shareaction.png
+++ b/docs/html/images/ui/actionbar-shareaction.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-shareaction@2x.png b/docs/html/images/ui/actionbar-shareaction@2x.png
new file mode 100644
index 0000000..d7e7cf7
--- /dev/null
+++ b/docs/html/images/ui/actionbar-shareaction@2x.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-splitaction.png b/docs/html/images/ui/actionbar-splitaction.png
new file mode 100644
index 0000000..6995d246
--- /dev/null
+++ b/docs/html/images/ui/actionbar-splitaction.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-splitaction@2x.png b/docs/html/images/ui/actionbar-splitaction@2x.png
new file mode 100644
index 0000000..8bc53b8
--- /dev/null
+++ b/docs/html/images/ui/actionbar-splitaction@2x.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-stacked.png b/docs/html/images/ui/actionbar-stacked.png
deleted file mode 100644
index 76c8908..0000000
--- a/docs/html/images/ui/actionbar-stacked.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/ui/actionbar-tabs-stacked.png b/docs/html/images/ui/actionbar-tabs-stacked.png
new file mode 100644
index 0000000..23ee0c2
--- /dev/null
+++ b/docs/html/images/ui/actionbar-tabs-stacked.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-tabs-stacked@2x.png b/docs/html/images/ui/actionbar-tabs-stacked@2x.png
new file mode 100644
index 0000000..dde19cc
--- /dev/null
+++ b/docs/html/images/ui/actionbar-tabs-stacked@2x.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-tabs.png b/docs/html/images/ui/actionbar-tabs.png
index 9d36db6..55746fe 100644
--- a/docs/html/images/ui/actionbar-tabs.png
+++ b/docs/html/images/ui/actionbar-tabs.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-tabs@2x.png b/docs/html/images/ui/actionbar-tabs@2x.png
new file mode 100644
index 0000000..7157522
--- /dev/null
+++ b/docs/html/images/ui/actionbar-tabs@2x.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-up.png b/docs/html/images/ui/actionbar-up.png
new file mode 100644
index 0000000..a797fb6
--- /dev/null
+++ b/docs/html/images/ui/actionbar-up.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar.png b/docs/html/images/ui/actionbar.png
index 1d01583..c748a51 100644
--- a/docs/html/images/ui/actionbar.png
+++ b/docs/html/images/ui/actionbar.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar@2x.png b/docs/html/images/ui/actionbar@2x.png
new file mode 100644
index 0000000..921ebf0
--- /dev/null
+++ b/docs/html/images/ui/actionbar@2x.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index d610899..a945f0a7 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -26,12 +26,12 @@
<a href="{@docRoot}about/versions/jelly-bean.html"><img src="{@docRoot}images/home/android-jellybean.png" ></a>
</div>
<div class="content-right col-6">
- <h1>More Jelly Beans!</h1>
+ <h1>A Sweeter Jelly Bean!</h1>
<p>Android 4.3 is now available with a variety of performance improvements
- and new developer features. </p>
- <p>With this release, Android now supports Bluetooth Low Energy for battery
- savings with wireless peripherals, OpenGL ES 3.0 for the most advanced mobile 3D
- graphics, MPEG DASH support for high quality media streaming, and much more.</p>
+ and new features. </p>
+ <p>For developers, the new platform adds support for <span style="white-space:nowrap;">OpenGL ES 3.0</span>,
+ connectivity with Bluetooth Smart devices and sensors, support for restricted profiles, a modular DRM framework,
+ new profiling tools, and more.</p>
<p><a href="{@docRoot}about/versions/jelly-bean.html" class="button">Learn More</a></p>
</div>
</li>
diff --git a/docs/html/sdk/exploring.jd b/docs/html/sdk/exploring.jd
index 9323f2e..7749060 100644
--- a/docs/html/sdk/exploring.jd
+++ b/docs/html/sdk/exploring.jd
@@ -77,7 +77,7 @@
</tr>
<tr>
- <td><a href="{@docRoot}tools/extras/support-library.html">Android Support</a></td>
+ <td><a href="{@docRoot}tools/support-library/index.html">Android Support</a></td>
<td>A static library you can include in your app sources in order to use powerful
APIs that aren't available in the standard platform. For example, the support library
contains versions of the {@link android.support.v4.app.Fragment} class that's compatible with
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 9a29599..5a47f85 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -398,7 +398,7 @@
<p>As you continue developing apps, you may need to install additional versions
of Android for the emulator and other packages such as the <a
-href="{@docRoot}tools/extras/support-library.html">Android Support Library</a>.
+href="{@docRoot}tools/support-library/index.html">Android Support Library</a>.
To install more packages, use
the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>, which you can
open from Android Studio by clicking <strong>SDK Manager</strong>
diff --git a/docs/html/sdk/win-usb.jd b/docs/html/sdk/win-usb.jd
index 802615e..5ca38c6 100644
--- a/docs/html/sdk/win-usb.jd
+++ b/docs/html/sdk/win-usb.jd
@@ -1,172 +1,315 @@
page.title=Google USB Driver
@jd:body
+
+
+<div style="position:relative;height:660px;">
+
+
+<div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+<div class="col-13" style="margin:0;"> </div><!-- provides top margin for content -->
+
+
+<p class="sdk-terms-intro">Before downloading the Google USB Driver,
+you must agree to the following terms and conditions.</p>
+
+<div class="sdk-terms" onfocus="this.blur()">
+<h2 class="norule">Terms and Conditions</h2>
+This is the Android Software Development Kit License Agreement
+
+<h3>1. Introduction</h3>
+1.1 The Android Software Development Kit (referred to in this License Agreement as the "SDK" and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is licensed to you subject to the terms of this License Agreement. This License Agreement forms a legally binding contract between you and Google in relation to your use of the SDK.
+
+1.2 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time.
+
+1.3 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
+
+
+<h3>2. Accepting this License Agreement</h3>
+2.1 In order to use the SDK, you must first agree to this License Agreement. You may not use the SDK if you do not accept this License Agreement.
+
+2.2 By clicking to accept, you hereby agree to the terms of this License Agreement.
+
+2.3 You may not use the SDK and may not accept the License Agreement if you are a person barred from receiving the SDK under the laws of the United States or other countries including the country in which you are resident or from which you use the SDK.
+
+2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to this License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the SDK on behalf of your employer or other entity.
+
+
+<h3>3. SDK License from Google</h3>
+3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, royalty-free, non-assignable and non-exclusive license to use the SDK solely to develop applications to run on the Android platform.
+
+3.2 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you.
+
+3.3 You may not use the SDK for any purpose not expressly permitted by this License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK.
+
+3.4 You agree that you will not take any actions that may cause or result in the fragmentation of Android, including but not limited to distributing, participating in the creation of, or promoting in any way a software development kit derived from the SDK.
+
+3.5 Use, reproduction and distribution of components of the SDK licensed under an open source software license are governed solely by the terms of that open source software license and not this License Agreement.
+
+3.6 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Google's sole discretion, without prior notice to you.
+
+3.7 Nothing in this License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features.
+
+3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the SDK.
+
+
+<h3>4. Use of the SDK by You</h3>
+4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under this License Agreement in or to any software applications that you develop using the SDK, including any intellectual property rights that subsist in those applications.
+
+4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) this License Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries).
+
+4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so.
+
+4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google or any mobile communications carrier.
+
+4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android and/or applications for Android, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so.
+
+4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under this License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach.
+
+
+<h3>5. Your Developer Credentials</h3>
+5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials.
+
+
+<h3>6. Privacy and Information</h3>
+6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be collected.
+
+6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's Privacy Policy.
+
+
+<h3>7. Third Party Applications</h3>
+7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources.
+
+7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners.
+
+7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, this License Agreement does not affect your legal relationship with these third parties.
+
+
+<h3>8. Using Android APIs</h3>
+8.1 Google Data APIs
+
+8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service.
+
+8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so.
+
+
+<h3>9. Terminating this License Agreement</h3>
+9.1 This License Agreement will continue to apply until terminated by either you or Google as set out below.
+
+9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of the SDK and any relevant developer credentials.
+
+9.3 Google may at any time, terminate this License Agreement with you if:
+(A) you have breached any provision of this License Agreement; or
+(B) Google is required to do so by law; or
+(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or
+(D) Google decides to no longer provide the SDK or certain parts of the SDK to users in the country in which you are resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially viable.
+
+9.4 When this License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst this License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely.
+
+
+<h3>10. DISCLAIMER OF WARRANTIES</h3>
+10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
+
+10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
+
+10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+
+
+<h3>11. LIMITATION OF LIABILITY</h3>
+11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
+
+
+<h3>12. Indemnification</h3>
+12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with this License Agreement.
+
+
+<h3>13. Changes to the License Agreement</h3>
+13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, Google will make a new version of the License Agreement available on the website where the SDK is made available.
+
+
+<h3>14. General Legal Terms</h3>
+14.1 This License Agreement constitutes the whole legal agreement between you and Google and governs your use of the SDK (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the SDK.
+
+14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in this License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google.
+
+14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this License Agreement is invalid, then that provision will be removed from this License Agreement without affecting the rest of this License Agreement. The remaining provisions of this License Agreement will continue to be valid and enforceable.
+
+14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to this License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of this License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to this License Agreement.
+
+14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
+
+14.6 The rights granted in this License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under this License Agreement without the prior written approval of the other party.
+
+14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
+
+
+<em>November 13, 2012</em>
+</div><!-- thin wrapper around tos doc -->
+
+
+<div id="usb-terms-form">
+<p>
+<input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+<label id="agreeLabel" for="agree">I have read and agree with the above terms and conditions</label>
+</p>
+<p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+</div>
+
+
+
+</div><!-- end TOS -->
+
+
+
+<div class="wrap col-13" style="margin:0" id="main">
+
+
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
- <li><a href="#notes">Revisions</a></li>
<li><a href="#WinUsbDriver">Downloading the Google USB Driver</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}tools/extras/oem-usb.html#InstallingDriver">Installing a USB Driver</a></li>
<li><a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a></li>
- <li><a href="{@docRoot}sdk/adding-components.html">Adding SDK Packages</a></li>
</ol>
+
+<h2>Get it</h2>
+
+<div class="download-box">
+ <a onclick="return onDownload(this)"
+ href="https://dl-ssl.google.com//android/repository/latest_usb_driver_windows.zip"
+ class="button" id="usbDriverButton">
+ Download Google USB Driver
+ </a>
+ <p class="filename">latest_usb_driver_windows.zip</p>
+</div>
+
</div>
</div>
-<p>The Google USB driver is a downloadable component for the Android SDK, available
-from the SDK Manager. The driver is for Windows only and provides the necessary drivers for the
-following devices:</p>
+<p>The Google USB Driver is for <strong>Windows only</strong> and provides the
+necessary drivers for the following devices:</p>
<ul>
<li>ADP1 / T-Mobile G1*</li>
<li>ADP2 / Google Ion / T-Mobile myTouch 3G*</li>
<li>Verizon Droid*</li>
<li>Nexus One</li>
<li>Nexus S</li>
+ <li>Nexus 4</li>
+ <li>Nexus 7</li>
+ <li>Nexus 10</li>
</ul>
<p>* <em>Or similar hardware on other carriers</em></p>
-
- <p>All other devices require Windows drivers provided by the hardware manufacturer, as listed in
-the <a href="{@docRoot}tools/extras/oem-usb.html">OEM USB Drivers</a> document. The Galaxy Nexus
-driver is also distributed by <a
+
+ <p>All other devices require Windows drivers provided by the respective hardware manufacturer,
+ as listed in the <a href="{@docRoot}tools/extras/oem-usb.html">OEM USB Drivers</a> document.</p>
+
+ <p>The Galaxy Nexus driver is distributed by <a
href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a>
(listed as model SCH-I515).</p>
<p class="note"><strong>Note:</strong>
-If you're developing on Mac OS X or Linux, then you do not need to install a USB driver. To start
-developing with your device, also read <a href="{@docRoot}guide/developing/device.html">Using
-Hardware Devices</a>.</p>
-
-<p>The sections below provide instructions on how to download and install the Google USB Driver
-for Windows. </p>
-
-
-
-
-<h2 id="notes">Revisions</h2>
-
-<p>The sections below provide notes about successive revisions of the USB Driver
-for Windows, as denoted by revision number. To determine what revision of the
-USB Driver for Windows you are using, refer to the "Installed Packages" listing
-in the Android SDK Manager.</p>
-
-<script type="text/javascript">
-function toggleDiv(link) {
- var toggleable = $(link).parent();
- if (toggleable.hasClass("closed")) {
- //$(".toggleme", toggleable).slideDown("fast");
- toggleable.removeClass("closed");
- toggleable.addClass("open");
- $(".toggle-img", toggleable).attr("title", "hide").attr("src", (toRoot + "assets/images/triangle-opened.png"));
- } else {
- //$(".toggleme", toggleable).slideUp("fast");
- toggleable.removeClass("open");
- toggleable.addClass("closed");
- $(".toggle-img", toggleable).attr("title", "show").attr("src", (toRoot + "assets/images/triangle-closed.png"));
- }
- return false;
-}
-</script>
-<style>
-.toggleable {
-padding: .25em 1em;
-}
-.toggleme {
- padding: 1em 1em 0 2em;
- line-height:1em;
-}
-.toggleable a {
- text-decoration:none;
-}
-.toggleme a {
- text-decoration:underline;
-}
-.toggleable.closed .toggleme {
- display:none;
-}
-#jd-content .toggle-img {
- margin:0;
-}
-</style>
-
-<div class="toggleable opened">
- <a href="#" onclick="return toggleDiv(this)">
- <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px"
-width="9px" />
-USB Driver for Windows, Revision 4</a> <em>(December 2010)</em>
- <div class="toggleme">
-
-<dl>
-<dt><p>Adds support for the Nexus S.</p></dt>
-</dl>
- </div>
-</div>
-
-<div class="toggleable closed">
- <a href="#" onclick="return toggleDiv(this)">
- <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px"
-width="9px" />
-USB Driver for Windows, Revision 3</a> <em>(January 2010)</em>
- <div class="toggleme">
-
-<dl>
-<dt><p>Adds support for the Nexus One.</p></dt>
-</dl>
- </div>
-</div>
-
-<div class="toggleable closed">
- <a href="#" onclick="return toggleDiv(this)">
- <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
-USB Driver for Windows, Revision 2</a> <em>(November 2009)</em>
- <div class="toggleme">
-
-<dl>
-<dt><p>Adds support for the Verizon Droid (or similar hardware on
-other carriers).</p></dt>
-</dl>
- </div>
-</div>
-
-<div class="toggleable closed">
- <a href="#" onclick="return toggleDiv(this)">
- <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
-USB Driver for Windows, Revision 1</a> <em>(October 2009)</em>
- <div class="toggleme">
-
-<dl>
-<dt><p>Initial release of the WinUsb-based driver, with support
-for the T-Mobile G1 and myTouch 3G (and similar devices).</p></dt>
-</dl>
- </div>
-</div>
+If you're developing on Mac OS X or Linux, then you <strong>do not</strong> need to install a USB
+driver. To start developing with your device, read
+<a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a>.</p>
<h2 id="WinUsbDriver">Downloading the Google USB Driver</h2>
+<p>The Google USB Driver for Windows is available for download as an optional SDK
+component. You need the driver only if you are developing on Windows and
+want to connect a Google Android-powered device (such as a Nexus 7) to your
+development environment over USB.</p>
+
<div class="figure" style="width:536px;margin:0">
<img src="{@docRoot}images/developing/sdk-usb-driver.png" alt="" />
<p class="img-caption"><strong>Figure 1.</strong> The SDK Manager
with the Google USB Driver selected.</p>
</div>
-<p>The USB Driver for Windows is available for download as an optional SDK
-component. You need the driver only if you are developing on Windows and
-want to connect an Android-powered device (ADP, Nexus One, or Nexus S) to your
-development environment over USB. </p>
+<p>You can download the Google USB Driver for Windows in one of two ways:</p>
+<ul>
+ <li>
+ <a onclick="$('#usbDriverButton').trigger('click');return false;" href="#">
+ Click here to download the latest Google USB Driver ZIP file</a>.</li>
+ <li>Or, use the Android SDK Manager tool that is
+included with the <a href="{@docRoot}sdk/index.html">Android SDK</a>. Using the SDK Manager
+helps you keep the driver up to date by notifying you when your current driver is out of date.
+ <ol>
+ <li>Launch the Android SDK Manager by double-clicking <code>SDK Manager.exe</code>,
+ at the root of your SDK directory.</li>
+ <li>Expand <em>Extras</em>.</li>
+ <li>Check <strong>Google USB Driver package</strong> and click <strong>Install</strong>.</li>
+ <li>Proceed to install the package. When done, the driver files are
+ downloaded into the <code><sdk>\extras\google\usb_driver\</code> directory.</li>
+ </ol>
+ </li>
+</ul>
-<p>To download the driver, use the Android SDK Manager tool that is
-included with the <a href="{@docRoot}sdk/index.html">Android SDK</a>:</p>
-<ol>
- <li>Launch the Android SDK Manager by double-clicking <code>SDK Manager.exe</code>,
- at the root of your SDK directory.</li>
- <li>Expand <em>Extras</em>.</li>
- <li>Check <strong>Google USB Driver package</strong> and click <strong>Install</strong>.</li>
- <li>Proceed to install the package. When done, the driver files are
-downloaded into the <code><sdk>\extras\google\usb_driver\</code> directory.</li>
-</ol>
+<p>For installation information, read
+<a href="{@docRoot}tools/extras/oem-usb.html#InstallingDriver">Installing a USB Driver</a>.</p>
-<p>For installation information, read <a href="{@docRoot}tools/extras/oem-usb.html#InstallingDriver">Installing a USB Driver</a>.</p>
+
+
+</div><!-- end wrap "main" for document content -->
+
+</div><!-- end outter wrapper for page contents -->
+
+
+
+
+<script>
+
+
+ function onDownload(link) {
+
+ /* set text for download button */
+ $("#downloadForRealz").html($(link).text());
+ $("#downloadForRealz").attr('href',$(link).attr('href'));
+
+ $("#tos").fadeIn('fast');
+ $("#main").fadeOut('fast');
+
+ location.hash = "download";
+ return false;
+ }
+
+
+ function onAgreeChecked() {
+ /* verify that the TOS is agreed and a bit version is chosen */
+ if ($("input#agree").is(":checked")) {
+ /* reveal the download button */
+ $("a#downloadForRealz").removeClass('disabled');
+ } else {
+ $("a#downloadForRealz").addClass('disabled');
+ }
+ }
+
+ function onDownloadForRealz(link) {
+ if ($("input#agree").is(':checked')) {
+ // OK, start the download and reset the page
+ $("input#agree").attr('checked',false);
+ $("a#downloadForRealz").addClass('disabled');
+ $("#tos").fadeOut('fast');
+ $("#main").fadeIn('fast');
+ location.hash = "top";
+ } else {
+ // Have not agreed to tos, make the checkbox blink
+ $("label#agreeLabel").parent().stop().animate({color: "#258AAF"}, 200,
+ function() {$("label#agreeLabel").parent().stop().animate({color: "#222"}, 200)}
+ );
+ return false;
+ }
+ }
+
+ $(window).hashchange( function(){
+ if (location.hash == "") {
+ location.reload();
+ }
+ });
+
+</script>
\ No newline at end of file
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 46164c1..6291a3e 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -164,7 +164,7 @@
http://developer.android.com/tools/sdk/eclipse-adt.html
http://developer.android.com/tools/revisions/platforms.html
http://developer.android.com/tools/extras/index.html
-http://developer.android.com/tools/extras/support-library.html
+http://developer.android.com/tools/support-library/index.html
http://developer.android.com/tools/extras/oem-usb.html
http://developer.android.com/tools/samples/index.html
http://developer.android.com/tools/adk/index.html
diff --git a/docs/html/tools/help/sdk-manager.jd b/docs/html/tools/help/sdk-manager.jd
index 215ce6f..276206f 100644
--- a/docs/html/tools/help/sdk-manager.jd
+++ b/docs/html/tools/help/sdk-manager.jd
@@ -55,7 +55,7 @@
a platform version as old as Android 1.6. All of the activity templates available when creating
a new project with the <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a>
require this. For more information, read <a
-href="{@docRoot}tools/extras/support-library.html">Support Library</a>.</dd>
+href="{@docRoot}tools/support-library/index.html">Support Library</a>.</dd>
<dt>SDK Samples</dt>
<dd>Recommended. The samples give you source code that you can use to learn about
Android, load as a project and run, or reuse in your own app. Note that multiple
diff --git a/docs/html/tools/publishing/preparing.jd b/docs/html/tools/publishing/preparing.jd
index 8e265f6..413b56e 100644
--- a/docs/html/tools/publishing/preparing.jd
+++ b/docs/html/tools/publishing/preparing.jd
@@ -271,7 +271,7 @@
<li><strong>Consider using the Support Library</strong>
<p>If your application is designed for devices running Android 3.x, make your application
compatible with older versions of Android by adding the
- <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> to your
+ <a href="{@docRoot}tools/support-library/index.html">Support Library</a> to your
application project. The Support Library provides static support libraries that you can add to
your Android application, which enables you to use APIs that are either not available on
older platform versions or use utility APIs that are not part of the framework APIs.</p>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index 1f34987..74caaf4 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -1,29 +1,29 @@
ndk=true
page.template=sdk
-ndk.mac64_download=android-ndk-r9-darwin-x86_64.tar.bz2
-ndk.mac64_bytes=726430529
-ndk.mac64_checksum=b975271d8f064611e7e12bf87b736826
+ndk.mac64_download=android-ndk-r8e-darwin-x86_64.tar.bz2
+ndk.mac64_bytes=508419298
+ndk.mac64_checksum=efac96fab20e6ddb1311d6ba5648ce72
-ndk.mac32_download=android-ndk-r9-darwin-x86.tar.bz2
-ndk.mac32_bytes=710781553
-ndk.mac32_checksum=6f7c4dd38df9079bb4b13846add5c0da
+ndk.mac32_download=android-ndk-r8e-darwin-x86.tar.bz2
+ndk.mac32_bytes=496238878
+ndk.mac32_checksum=e17e707464c45c0d5615e4d0ae6a5cf7
-ndk.linux64_download=android-ndk-r9-linux-x86_64.tar.bz2
-ndk.linux64_bytes=669064468
-ndk.linux64_checksum=3eedc86b20ec09fcd1fd03f4481a706d
+ndk.linux64_download=android-ndk-r8e-linux-x86_64.tar.bz2
+ndk.linux64_bytes=466853553
+ndk.linux64_checksum=fa812352956067e7a9eefc0274675e9a
-ndk.linux32_download=android-ndk-r9-linux-x86.tar.bz2
-ndk.linux32_bytes=660787157
-ndk.linux32_checksum=999d155ba772c49baacee6d41d664922
+ndk.linux32_download=android-ndk-r8e-linux-x86.tar.bz2
+ndk.linux32_bytes=461526099
+ndk.linux32_checksum=26d774b0884bcd98de08eb4de41ab532
-ndk.win64_download=android-ndk-r9-windows-x86_64.zip
-ndk.win64_bytes=826661995
-ndk.win64_checksum=cd56cc1036235f16369f2112fa27be91
+ndk.win64_download=android-ndk-r8e-windows-x86_64.zip
+ndk.win64_bytes=461298980
+ndk.win64_checksum=11eb99b3b56fc86d9d231ebff5c41db3
-ndk.win32_download=android-ndk-r9-windows-x86.zip
-ndk.win32_bytes=777938252
-ndk.win32_checksum=9c1f66ff963cc61e338964c5f97a4d34
+ndk.win32_download=android-ndk-r8e-windows-x86.zip
+ndk.win32_bytes=434701805
+ndk.win32_checksum=fb41ed2bff5610b14a7b6f085ab86213
page.title=Android NDK
@jd:body
@@ -255,286 +255,13 @@
<h2 id="Revisions">Revisions</h2>
-<p>The following sections provide information about releases of the NDK.</p>
+<p>The sections below provide information and notes about successive releases of
+the NDK, as denoted by revision number. </p>
+
<div class="toggle-content opened">
- <p>
- <a href="#" onclick="return toggleContent(this)"> <img
- src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
- >Android NDK, Revision 9</a> <em>(July 2013)</em>
- </p>
- <div class="toggle-content-toggleme">
- <dl>
- <dt>Important changes:</dt>
- <dd>
- <ul>
- <li>Added support for Android 4.3 (API level 18). For more information, see
- {@code STABLE-APIS.html} and new code examples in {@code samples/gles3jni/README}.
- <li>Added headers and libraries for OpenGL ES 3.0, which is supported by Android 4.3
- (API level 18) and higher.</li>
- <li>Added GNU Compiler Collection (GCC) 4.8 compiler to the NDK. Since GCC 4.6 is still
- the default, you must explicitly enable this option:
- <ul>
- <li>For {@code ndk-build} builds, export {@code NDK_TOOLCHAIN_VERSION=4.8} or
- add it in {@code Application.mk}.</li>
- <li>For standalone builds, use the {@code --toolchain=} option in
- {@code make-standalone-toolchain.sh}, for example:<br>
- {@code --toolchain=arm-linux-androideabi-4.8}</li>
- </ul>
- <p class="note"><strong>Note:</strong>
- The {@code -Wunused-local-typedefs} option is enabled by {@code -Wall}. Be
- sure to add {@code __attribute__((unused))} if you use compile-time asserts like
- {@code sources/cxx-stl/stlport/stlport/stl/config/features.h}, line #311. For more
- information, see
- <a href="https://android-review.googlesource.com/#/c/55460">Change 55460</a></p>
- <p class="note"><strong>Note:</strong>
- In the GCC 4.7 release and later, ARM compilers generate unaligned access code by
- default for ARMv6 and higher build targets. You may need to add the
- {@code -mno-unaligned-access} build option when building for kernels that do not support
- this feature.</p>
- </li>
- <li>Added Clang 3.3 support. The {@code NDK_TOOLCHAIN_VERSION=clang} build option
- now picks Clang 3.3 by default.
- <p class="note"><strong>Note:</strong>
- Both GCC 4.4.3 and Clang 3.1 are deprecated, and will be removed from the next NDK
- release.</p></li>
- <li>Updated GNU Project Debugger (GDB) to support python 2.7.5.</li>
- <li>Added MCLinker to support Windows hosts. Since {@code ld.gold}
- is the default where available, you must add {@code -fuse-ld=mcld} in
- {@code LOCAL_LDFLAGS} or {@code APP_LDFLAGS} to enable MCLinker.</li>
- <li>Added {@code ndk-depends} tool which prints ELF library dependencies.
- For more information, see {@code NDK-DEPENDS.html}.
- (<a href="http://b.android.com/53486">Issue 53486</a>)</li>
- </ul>
- </dd>
-
- <dt>Important bug fixes:</dt>
- <dd>
- <ul>
- <li>Fixed potential event handling issue in {@code android_native_app_glue}.
- (<a href="http://b.android.com/41755">Issue 41755</a>)</li>
- <li>Fixed ARM/GCC-4.7 build to generate sufficient alignment for NEON load and store
- instructions VST and VLD.
- (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57271">GCC Issue 57271</a>)</li>
- <li>Fixed a GCC 4.4.3/4.6/4.7 internal compiler error (ICE) for a constant negative index
- value on a string literal.
- (<a href="http://b.android.com/54623">Issue 54623</a>)</li>
- <li>Fixed GCC 4.7 segmentation fault for constant initialization with an object address.
- (<a href="http://b.android.com/56508">Issue 56508</a>)</li>
- <li>Fixed GCC 4.6 ARM segmentation fault for <code>-O</code> values when using Boost
- 1.52.0. (<a href="http://b.android.com/42891">Issue 42891</a>)
- <li>Fixed {@code libc.so} and {@code libc.a} to support the {@code wait4()} function.
- (<a href="http://b.android.com/19854">Issue 19854</a>)</li>
- <li>Updated the x86 libc.so and libc.a files to include the {@code clone()}
- function.</li>
- <li>Fixed {@code LOCAL_SHORT_COMMANDS} bug where the {@code linker.list} file is
- empty or not used.</li>
- <li>Fixed GCC MIPS build on Mac OS to use CFI directives, without which
- {@code ld.mcld --eh-frame-hdr} fails frequently.</li>
- <li>Fixed Clang 3.2 X86/MIPS internal compiler error in {@code llvm/lib/VMCore/Value.cpp}.
- (<a href="https://android-review.googlesource.com/#/c/59021">Change 59021</a>)</li>
- <li>Fixed GCC 4.7 64-bit Windows assembler crash. (Error: {@code out of memory allocating
- 4294967280 bytes}).</li>
- <li>Updated {@code ndk-gdb} script so that the {@code --start} or {@code --launch} actions
- now wait for the GNU Debug Server, so that it can more reliably hit breakpoints set
- early in the execution path (such as breakpoints in JNI code).
- (<a href="http://b.android.com/41278">Issue 41278</a>)
- <p class="note"><strong>Note:</strong>
- This feature requires jdb and produces warning about pending breakpoints.
- Specify the {@code --nowait} option to restore previous behavior.
- </p>
- </li>
- <li>Fixed GDB crash when library list is empty.</li>
- <li>Fixed GDB crash when using a {@code stepi} command past a {@code bx pc} or
- {@code blx pc} Thumb instruction.
- (<a href="http://b.android.com/56962">Issue 56962</a>,
- <a href="http://b.android.com/36149">Issue 36149</a>)</li>
- <li>Fixed MIPS {@code gdbserver} to look for {@code DT_MIPS_RLD_MAP} instead of
- {@code DT_DEBUG}. (<a href="http://b.android.com/56586">Issue 56586</a>)</li>
- <li>Fixed a circular dependency in the ndk-build script, for example: If A->B and
- B->B, then B was dropped from build.
- (<a href="http://b.android.com/56690">Issue 56690</a>)</li>
- </ul>
- </dd>
-
- <dt>Other bug fixes:</dt>
- <dd>
- <ul>
- <li>Fixed the {@code ndk-build} script to enable you to specify a version of Clang as a
- command line option (e.g., {@code NDK_TOOLCHAIN_VERSION=clang3.2}). Previously, only
- specifying the version as an environment variable worked.</li>
- <li>Fixed gabi++ size of {@code _Unwind_Exception} to be 24 for MIPS build targets when
- using the Clang compiler.
- (<a href="https://android-review.googlesource.com/#/c/54141">Change 54141</a>)</li>
- <li>Fixed the {@code ndk-build} script to ensure that built libraries are actually
- removed from projects that include prebuilt static libraries when using the
- {@code ndk-build clean} command.
- (<a href="https://android-review.googlesource.com/#/c/54461">Change 54461</a>,
- <a href="https://android-review.googlesource.com/#/c/54480">Change 54480</a>)</li>
- <li>Modified the {@code NDK_ANALYZE=1} option to be less verbose.</li>
- <li>Fixed {@code gnu-libstdc++/Android.mk} to include a {@code backward/} path for builds
- that use backward compability.
- (<a href="http://b.android.com/53404">Issue 53404</a>)</li>
- <li>Fixed a problem where {@code stlport new} sometimes returned random values.</li>
- <li>Fixed {@code ndk-gdb} to match the order of {@code CPU_ABIS}, not {@code APP_ABIS}.
- (<a href="http://b.android.com/54033">Issue 54033</a>)</li>
- <li>Fixed a problem where the NDK 64-bit build on MacOSX choses the wrong path for
- compiler.
- (<a href="http://b.android.com/53769">Issue 53769</a>)</li>
- <li>Fixed build scripts to detect 64-bit Windows Vista.
- (<a href="http://b.android.com/54485">Issue 54485</a>)</li>
- <li>Fixed x86 {@code ntonl/swap32} error: {@code invalid 'asm': operand number
- out of range}.
- (<a href="http://b.android.com/54465">Issue 54465</a>,
- <a href="https://android-review.googlesource.com/#/c/57242">Change 57242</a>)</li>
- <li>Fixed {@code ld.gold} to merge string literals.</li>
- <li>Fixed {@code ld.gold} to handle large symbol alignment.</li>
- <li>Updated {@code ld.gold} to enable the {@code --sort-section=name} option.</li>
- <li>Fixed GCC 4.4.3/4.6/4.7 to suppress the {@code -export-dynamic} option for
- statically linked programs. GCC no longer adds an {@code .interp} section for statically
- linked programs.</li>
- <li>Fixed GCC 4.4.3 {@code stlport} compilation error about inconsistent {@code typedef}
- of {@code _Unwind_Control_Block}.
- (<a href="http://b.android.com/54426">Issue 54426</a>)</li>
- <li>Fixed {@code awk} scripts to handle {@code AndroidManifest.xml} files created on
- Windows which may contain trailing {@code \r} characters and cause build errors.
- (<a href="http://b.android.com/42548">Issue 42548</a>)</li>
- <li>Fixed {@code make-standalone-toolchain.sh} to probe the {@code prebuilts/}
- directory to detect if the host is 32 bit or 64 bit.</li>
- <li>Fixed the Clang 3.2 {@code -integrated-as} option.</li>
- <li>Fixed the Clang 3.2 ARM EHABI compact model {@code pr1} and {@code pr2} handler data.
- </li>
- <li>Added clang {@code -mllvm -arm-enable-ehabi} option to fix the following clang error:
- <pre>clang: for the -arm-enable-ehabi option: may only occur zero or one times!</pre>
- </li>
- <li>Fixed build failure when there is no {@code uses-sdk} element in application
- manifest. (<a href="http://b.android.com/57015">Issue 57015</a>)</li>
- </ul>
-
- </dd>
- <dt>Other changes:</dt>
- <dd>
- <ul>
- <li>Header Fixes
- <ul>
- <li>Modified headers to make {@code __set_errno} an inlined function, since
- {@code __set_errno} in {@code errno.h} is deprecated, and {@code libc.so} no longer
- exports it.</li>
- <li>Modified {@code elf.h} to include {@code stdint.h}.
- (<a href="http://b.android.com/55443">Issue 55443</a>)</li>
- <li>Fixed {@code sys/un.h} to be included independently of other headers.
- (<a href="http://b.android.com/53646">Issue 53646</a>)</li>
- <li>Fixed all of the {@code MotionEvent_getHistorical} API family to take the
- {@code const AInputEvent* motion_event}.
- (<a href="http://b.android.com/55873">Issue 55873</a>)</li>
- <li>Fixed {@code malloc_usable_size} to take {@code const void*}.
- (<a href="http://b.android.com/55725">Issue 55725</a>)</li>
- <li>Fixed stdint.h to be more compatible with C99.
- (<a href="https://android-review.googlesource.com/#/c/46821">Change 46821</a>)</li>
- <li>Modified {@code wchar.h} to not redefine {@code WCHAR_MAX} and
- {@code WCHAR_MIN}</li>
- <li>Fixed {@code <inttypes.h>} declaration for pointer-related {@code PRI} and
- {@code SCN} macros. (<a href="http://b.android.com/57218">Issue 57218</a>)</li>
- <li>Changed the {@code sys/cdefs.h} header so that {@code __WCHAR_TYPE__} is 32-bit
- for API levels less than 9, which means that {@code wchat_t} is 32-bit for all
- API levels. To restore the previous behavior, define the {@code _WCHAR_IS_8BIT}
- boolean variable. (<a href="http://b.android.com/57267">Issue 57267</a>)</li>
- </ul>
- </li>
- <li>Added more formatting in NDK {@code docs/} and miscellaneous documentation fixes.
- </li>
- <li>Added support for a thin archive technique when building static libraries.
- (<a href="http://b.android.com/40303">Issue 40303</a>)</li>
- <li>Updated script {@code make-standalone-toolchain.sh} to support the {@code stlport}
- library in addition to {@code gnustl}, when you specify the option
- {@code --stl=stlport}. For more information, see {@code STANDALONE-TOOLCHAIN.html}.</li>
- <li>Updated the {@code make-standalone-toolchain.sh} script so that the
- {@code --llvm-version=} option creates the {@code $TOOLCHAIN_PREFIX-clang} and
- {@code $TOOLCHAIN_PREFIX-clang++} scripts in addition to {@code clang} and
- {@code clang++}, to avoid using the host's clang and clang++ definitions by accident.
- </li>
- <li>Added two flags to re-enable two optimizations in upstream Clang but disabled in
- NDK for better compatibility with code compiled by GCC:
- <ul>
- <li>Added a {@code -fcxx-missing-return-semantics} flag to re-enable <em>missing return
- semantics</em> in Clang 3.2+. Normally, all paths should terminate with a return
- statement for a value-returning function. If this is not the case, clang inserts
- an undefined instruction (or trap in debug mode) at the path without a return
- statement. If you are sure your code is correct, use this flag to allow the
- optimizer to take advantage of the undefined behavior. If you are not sure, do not
- use this flag. The caller may still receive a random incorrect value, but the
- optimizer will not exploit it and make your code harder to debug.</li>
- <li>Added a {@code -fglobal-ctor-const-promotion} flag to re-enable
- promoting global variables with static constructor to be constants. With this flag,
- the global variable optimization pass of LLVM tries to evaluate the global
- variables with static constructors and promote them to global constants. Although
- this optimization is correct, it may cause some incompatability with code compiled
- by GCC. For example, code may do {@code const_cast} to cast the constant to mutable
- and modify it. In GCC, the variable is in read-write and the code is run by
- accident. In Clang, the const variable is in read-only memory and may cause your
- application to crash.</li>
- </ul>
- </li>
- <li>Added {@code -mldc1-sdc1} to the MIPS GCC and Clang compilers. By default, compilers
- align 8-byte objects properly and emit the {@code ldc1} and {@code sdc1} instructions
- to move them around. If your app uses a custom allocator that does not always align
- with a new object's 8-byte boundary in the same way as the default allocator, your app
- may crash due to {@code ldc1} and {@code sdc1} operations on unaligned memory. In this
- case, use the {@code -mno-ldc1-sdc1} flag to workaround the problem.</li>
- <li>Downgraded the event severity from warning to info if {@code APP_PLATFORM_LEVEL} is
- larger than {@code APP_MIN_PLATFORM_LEVEL}. The {@code APP_PLATFORM_LEVEL} may be lower
- than {@code APP_PLATFORM} in {@code jni/Application.mk} because the NDK does not have
- headers for all levels. In this case, the actual level is shifted downwards. The
- {@code APP_MIN_PLATFORM_LEVEL} is specified by the {@code android:minSdkVersion} in
- your application's manifest.
- (<a href="http://b.android.com/39752">Issue 39752</a>)</li>
- <li>Added the {@code android_getCpuIdArm()} and {@code android_setCpuArm()} methods to
- {@code cpu-features.c}. This addition enables easier retrieval of the ARM CPUID
- information. (<a href="http://b.android.com/53689">Issue 53689</a>)</li>
- <li>Modified {@code ndk-build} to use GCC 4.7's {@code as/ld} for Clang compiling.
- <p class="note"><strong>Note:</strong>
- In GCC 4.7, {@code monotonic_clock} and {@code is_monotonic} have been renamed to
- {@code steady_clock} and {@code is_steady}, respectively.</p></li>
- <li>Added the following new warnings to the {@code ndk-build} script:
- <ul>
- <li>Added warnings if {@code LOCAL_LDLIBS/LDFLAGS} are used in static library
- modules.</li>
- <li>Added a warning if a configuration has no module to build.</li>
- <li>Added a warning for non-system libraries being used in
- {@code LOCAL_LDLIBS/LDFLAGS} of a shared library or executable modules.</li>
- </ul>
- </li>
- <li>Updated build scripts, so that if {@code APP_MODULES} is not defined and only static
- libraries are listed in {@code Android.mk}, the script force-builds all of them.
- (<a href="http://b.android.com/53502">Issue 53502</a>)</li>
- <li>Updated {@code ndk-build} to support absolute paths in {@code LOCAL_SRC_FILES}.</li>
- <li>Removed the {@code *-gdbtui} executables, which are duplicates of the {@code *-gdb}
- executables with the {@code -tui} option enabled.</li>
- <li>Updated the build scripts to warn you when the Edison Design Group (EDG) compiler
- front-end turns {@code _STLP_HAS_INCLUDE_NEXT} back on.
- (<a href="http://b.android.com/53646">Issue 53646</a>)</li>
- <li>Added the environment variable {@code NDK_LIBS_OUT} to allow overriding of the
- path for {@code libraries/gdbserver} from the default {@code $PROJECT/libs}.
- For more information, see {@code OVERVIEW.html}.</li>
- <li>Changed ndk-build script defaults to compile code with format string protection
- {@code -Wformat -Werror=format-security}. You may set
- {@code LOCAL_DISABLE_FORMAT_STRING_CHECKS=true} to disable it.
- For more information, see {@code ANDROID-MK.html}</li>
- <li>Added STL pretty-print support in {@code ndk-gdb-py}. For more information, see
- {@code NDK-GDB.html}.</li>
- <li>Added tests based on the googletest frameworks.</li>
- <li>Added a notification to the toolchain build script that warns you if the current shell
- is not {@code bash}.</li>
- </ul>
- </dd>
- </dl>
- </div>
-</div>
-
-
-<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
- <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+ <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
alt="">Android NDK, Revision 8e</a> <em>(March 2013)</em>
</p>
@@ -556,7 +283,7 @@
build automatically sorts out the order of libraries specified in
{@code LOCAL_STATIC_LIBRARIES}, {@code LOCAL_WHOLE_STATIC_LIBRARIES} and
{@code LOCAL_SHARED_LIBRARIES}. For more information, see {@code CHANGES.HTML}.
- (<a href="http://b.android.com/39378">Issue 39378</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39378">Issue 39378</a>)</li>
</ul>
</dd>
@@ -568,23 +295,23 @@
<li>Fixed build script which unconditionally builds Clang/llvm for MacOSX in 64-bit.</li>
<li>Fixed GCC 4.6/4.7 internal compiler error:
{@code gen_thumb_movhi_clobber at config/arm/arm.md:5832}.
- (<a href="http://b.android.com/52732">Issue 52732</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=52732">Issue 52732</a>)</li>
<li>Fixed build problem where GCC/ARM 4.6/4.7 fails to link code using 64-bit atomic
built-in functions.
- (<a href="http://b.android.com/41297">Issue 41297</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=41297">Issue 41297</a>)</li>
<li>Fixed GCC 4.7 linker DIV usage mismatch errors.
(<a href="http://sourceware.org/ml/binutils/2012-12/msg00202.html">Sourceware Issue</a>)
<li>Fixed GCC 4.7 internal compiler error {@code build_data_member_initialization, at
cp/semantics.c:5790}.</li>
<li>Fixed GCC 4.7 internal compiler error {@code redirect_eh_edge_1, at tree-eh.c:2214}.
- (<a href="http://b.android.com/52909">Issue 52909</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=52909">Issue 52909</a>)</li>
<li>Fixed a GCC 4.7 segfault.
(<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55245">GCC Issue</a>)</li>
<li>Fixed {@code <chrono>} clock resolution and enabled {@code steady_clock}.
- (<a href="http://b.android.com/39680">Issue 39680</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39680">Issue 39680</a>)</li>
<li>Fixed toolchain to enable {@code _GLIBCXX_HAS_GTHREADS} for GCC 4.7 libstdc++.
- (<a href="http://b.android.com/41770">Issue 41770</a>,
- <a href="http://b.android.com/41859">Issue 41859</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=41770">Issue 41770</a>,
+ <a href="http://code.google.com/p/android/issues/detail?id=41859">Issue 41859</a>)</li>
<li>Fixed problem with the X86 MXX/SSE code failing to link due to missing
{@code posix_memalign}.
(<a href="https://android-review.googlesource.com/#/c/51872">Change 51872</a>)</li>
@@ -594,24 +321,24 @@
<li>Fixed GCC4.7/X86 to restore earlier {@code cmov} behavior.
(<a href="http://gcc.gnu.org/viewcvs?view=revision&revision=193554">GCC Issue</a>)</li>
<li>Fixed handling NULL return value of {@code setlocale()} in libstdc++/GCC4.7.
- (<a href="http://b.android.com/46718">Issue 46718</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=46718">Issue 46718</a>)
<li>Fixed {@code ld.gold} runtime undefined reference to {@code __exidx_start} and
{@code __exidx_start_end}.
(<a href="https://android-review.googlesource.com/#/c/52134">Change 52134</a>)</li>
<li>Fixed Clang 3.1 internal compiler error when using Eigen library.
- (<a href="http://b.android.com/41246">Issue 41246</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=41246">Issue 41246</a>)</li>
<li>Fixed Clang 3.1 internal compiler error including {@code <chrono>} in C++11 mode.
- (<a href="http://b.android.com/39600">Issue 39600</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39600">Issue 39600</a>)</li>
<li>Fixed Clang 3.1 internal compiler error when generating object code for a method
call to a uniform initialized {@code rvalue}.
- (<a href="http://b.android.com/41387">Issue 41387</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=41387">Issue 41387</a>)</li>
<li>Fixed Clang 3.1/X86 stack realignment.
(<a href="https://android-review.googlesource.com/#/c/52154">Change 52154</a>)</li>
<li>Fixed problem with GNU Debugger (GDB) SIGILL when debugging on Android 4.1.2.
- (<a href="http://b.android.com/40941">Issue 40941</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=40941">Issue 40941</a>)</li>
<li>Fixed problem where GDB cannot set {@code source:line} breakpoints when symbols contain
long, indirect file paths.
- (<a href="http://b.android.com/42448">Issue 42448</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=42448">Issue 42448</a>)</li>
<li>Fixed GDB {@code read_program_header} for MIPS PIE executables.
(<a href="https://android-review.googlesource.com/#/c/49592">Change 49592</a>)</li>
<li>Fixed {@code STLport} segmentation fault in {@code uncaught_exception()}.
@@ -619,7 +346,7 @@
<li>Fixed {@code STLport} bus error in exception handling due to unaligned access of
{@code DW_EH_PE_udata2}, {@code DW_EH_PE_udata4}, and {@code DW_EH_PE_udata8}.</li>
<li>Fixed Gabi++ infinite recursion problem with {@code nothrow new[]} operator.
- (<a href="http://b.android.com/52833">Issue 52833</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=52833">Issue 52833</a>)</li>
<li>Fixed Gabi++ wrong offset to exception handler pointer.
(<a href="https://android-review.googlesource.com/#/c/53446">Change 53446</a>)</li>
<li>Removed Gabi++ redundant free on exception object
@@ -638,11 +365,11 @@
<li>Fixed {@code stddef.h} to not redefine {@code offsetof} since it already exists
in the toolchain.</li>
<li>Fixed {@code elf.h} to contain {@code Elf32_auxv_t} and {@code Elf64_auxv_t}.
- (<a href="http://b.android.com/38441">Issue 38441</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=38441">Issue 38441</a>)
</li>
<li>Fixed the {@code #ifdef} C++ definitions in the
{@code OpenSLES_AndroidConfiguration.h} header file.
- (<a href="http://b.android.com/53163">Issue 53163</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=53163">Issue 53163</a>)
</li>
</ul>
</li>
@@ -650,7 +377,7 @@
</li>
<li>Fixed system and Gabi++ headers to be able to compile with API level 8 and lower.</li>
<li>Fixed {@code cpufeatures} to not parse {@code /proc/self/auxv}.
- (<a href="http://b.android.com/43055">Issue 43055</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=43055">Issue 43055</a>)</li>
<li>Fixed {@code ld.gold} to not depend on host libstdc++ and on Windows platforms,
to not depend on the {@code libgcc_sjlj_1.dll} library.</li>
<li>Fixed Clang 3.1 which emits inconsistent register list in {@code .vsave} and fails
@@ -667,16 +394,16 @@
</li>
<li>Fixed X86 {@code libc.so} and {@code lib.a} which were missing the {@code sigsetjmp}
and {@code siglongjmp} functions already declared in {@code setjmp.h}.
- (<a href="http://b.android.com/19851">Issue 19851</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=19851">Issue 19851</a>)</li>
<li>Patched GCC 4.4.3/4.6/4.7 libstdc++ to work with Clang in C++ 11.
(<a href="http://clang.llvm.org/cxx_status.html">Clang Issue</a>)</li>
<li>Fixed cygwin path in argument passed to {@code HOST_AWK}.</li>
<li>Fixed {@code ndk-build} script warning in windows when running from project's JNI
directory.
- (<a href="http://b.android.com/40192">Issue 40192</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=40192">Issue 40192</a>)</li>
<li>Fixed problem where the {@code ndk-build} script does not build if makefile has
trailing whitespace in the {@code LOCAL_PATH} definition.
- (<a href="http://b.android.com/42841">Issue 42841</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=42841">Issue 42841</a>)</li>
</ul>
</dd>
@@ -692,13 +419,13 @@
hidden visibility except for exception handling helpers.</li>
<li>Updated build so that {@code STLport} is built for ARM in Thumb mode.</li>
<li>Added support for {@code std::set_new_handler} in Gabi++.
- (<a href="http://b.android.com/52805">Issue 52805</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=52805">Issue 52805</a>)</li>
<li>Enabled {@code FUTEX} system call in GNU libstdc++.</li>
<li>Updated {@code ndk-build} so that it no longer copies prebuilt static library to
a project's {@code obj/local/<abi>/} directory.
- (<a href="http://b.android.com/40302">Issue 40302</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=40302">Issue 40302</a>)</li>
<li>Removed {@code __ARM_ARCH_5*__} from ARM {@code toolchains/*/setup.mk} script.
- (<a href="http://b.android.com/21132">Issue 21132</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=21132">Issue 21132</a>)</li>
<li>Built additional GNU libstdc++ libraries in thumb for ARM.</li>
<li>Enabled MIPS floating-point {@code madd/msub/nmadd/nmsub/recip/rsqrt}
instructions with 32-bit FPU.</li>
@@ -731,7 +458,7 @@
which was preventing a significant amount of parallel build processing.</li>
<li>Updated {@code build-gabi++.sh} and {@code build-stlport.sh} so they can now run
from the NDK package.
- (<a href="http://b.android.com/52835">Issue 52835</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=52835">Issue 52835</a>)
</li>
<li>Fixed {@code run-tests.sh} in the {@code MSys} utilities collection.</li>
<li>Improved 64-bit host toolchain and Canadian Cross build support.</li>
@@ -813,7 +540,7 @@
<dd>
<ul>
<li>Fixed unnecessary rebuild of object files when using the {@code ndk-build} script.
- (<a href="http://b.android.com/39810">Issue 39810</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39810">Issue 39810</a>)</li>
<li>Fixed a linker failure with the NDK 8c release for Mac OS X 10.6.x that produced the
following error:
<pre>
@@ -824,29 +551,29 @@
not compatible with Mac OS 10.6.x and the NDK.
</li>
<li>Removed the {@code -x c++} options from the Clang++ standalone build script.
- (<a href="http://b.android.com/39089">Issue 39089</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39089">Issue 39089</a>)</li>
<li>Fixed issues using the {@code NDK_TOOLCHAIN_VERSION=clang3.1} option in Cygwin.
- (<a href="http://b.android.com/39585">Issue 39585</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li>
<li>Fixed the {@code make-standalone-toolchain.sh} script to allow generation of a
standalone toolchain using the Cygwin or MinGW environments. The resulting toolchain
can be used in Cygwin, MingGW or CMD.exe environments.
- (<a href="http://b.android.com/39915">Issue 39915</a>,
- <a href="http://b.android.com/39585">Issue 39585</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39915">Issue 39915</a>,
+ <a href="http://code.google.com/p/android/issues/detail?id=39585">Issue 39585</a>)</li>
<li>Added missing {@code SL_IID_ANDROIDBUFFERQUEUESOURCE} option in android-14 builds for
ARM and X86.
- (<a href="http://b.android.com/40625">Issue 40625</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=40625">Issue 40625</a>)</li>
<li>Fixed x86 CPU detection for the {@code ANDROID_CPU_X86_FEATURE_MOVBE} feature.
- (<a href="http://b.android.com/39317">Issue 39317</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=39317">Issue 39317</a>)</li>
<li>Fixed an issue preventing the Standard Template Library (STL) from using C++
sources that do not have a {@code .cpp} file extension.</li>
<li>Fixed GCC 4.6 ARM internal compiler error <em>at reload1.c:1061</em>.
- (<a href="http://b.android.com/20862">Issue 20862</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=20862">Issue 20862</a>)</li>
<li>Fixed GCC 4.4.3 ARM internal compiler error <em>at emit-rtl.c:1954</em>.
- (<a href="http://b.android.com/22336">Issue 22336</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=22336">Issue 22336</a>)</li>
<li>Fixed GCC 4.4.3 ARM internal compiler error <em>at postreload.c:396</em>.
- (<a href="http://b.android.com/22345">Issue 22345</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=22345">Issue 22345</a>)</li>
<li>Fixed problem with GCC 4.6/4.7 skipping lambda functions.
- (<a href="http://b.android.com/35933">Issue 35933</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=35933">Issue 35933</a>)</li>
</ul>
</dd>
@@ -857,21 +584,21 @@
<ul>
<li>Fixed {@code __WINT_TYPE__} and {@code wint_t} to be the same type.</li>
<li>Corrected typo in {@code android/bitmap.h}.
- (<a href="http://b.android.com/15134">Issue 15134</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=15134">Issue 15134</a>)
</li>
<li>Corrected typo in {@code errno.h}.</li>
<li>Added check for the presence of {@code __STDC_VERSION__} in {@code sys/cdefs.h}.
- (<a href="http://b.android.com/14627">Issue 14627</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=14627">Issue 14627</a>)
</li>
<li>Reorganized headers in {@code byteswap.h} and {@code dirent.h}.</li>
<li>Fixed {@code limits.h} to include {@code page.h} which provides {@code PAGE_SIZE}
settings.
- (<a href="http://b.android.com/39983">Issue 39983</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=39983">Issue 39983</a>)
</li>
<li>Fixed return type of {@code glGetAttribLocation()} and
{@code glGetUniformLocation()} from {@code int} to {@code GLint}.</li>
<li>Fixed {@code __BYTE_ORDER} constant for x86 builds.
- (<a href="http://b.android.com/39824">Issue 39824</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=39824">Issue 39824</a>)
</li>
</ul>
</li>
@@ -884,7 +611,7 @@
<li>Fixed ARM EHABI support in Clang to conform to specifications.</li>
<li>Fixed GNU Debugger (GDB) to shorten the time spent on walking the target's link map
during {@code solib} events.
- (<a href="http://b.android.com/38402">Issue 38402</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=38402">Issue 38402</a>)</li>
<li>Fixed missing {@code libgcc.a} file when linking shared libraries.</li>
</ul>
</dd>
@@ -985,7 +712,7 @@
<ul>
<li>Fixed an issue where running {@code make-standalone-toolchain.sh} with root privileges
resulted in the stand alone tool chain being inaccessible to some users.
- (<a href="http://b.android.com/35279">Issue 35279</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=35279">Issue 35279</a>)
<ul>
<li>All files and executables in the NDK release package are set to have read and
execute permissions for all.</li>
@@ -995,23 +722,23 @@
<li>Removed redundant {@code \r} from Windows prebuilt {@code echo.exe}. The redundant
{@code \r} caused {@code gdb.setup} to fail in the GNU Debugger (GDB) because it
incorrectly became part of the path.
- (<a href="http://b.android.com/36054">Issue 36054</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=36054">Issue 36054</a>)</li>
<li>Fixed Windows parallel builds that sometimes failed due to timing issues in the
{@code host-mkdir} implementation.
- (<a href="http://b.android.com/25875">Issue 25875</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=25875">Issue 25875</a>)</li>
<li>Fixed GCC 4.4.3 GNU {@code libstdc++} to <em>not</em> merge {@code typeinfo} names by
default. For more details, see
{@code toolchain repo gcc/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo}.
- (<a href="http://b.android.com/22165">Issue 22165</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=22165">Issue 22165</a>)</li>
<li>Fixed problem on {@code null} context in GCC 4.6
{@code cp/mangle.c::write_unscoped_name}, where GCC may crash when the context is
{@code null} and dereferenced in {@code TREE_CODE}.</li>
<li>Fixed GCC 4.4.3 crashes on ARM NEON-specific type definitions for floats.
- (<a href="http://b.android.com/34613">Issue 34613</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=34613">Issue 34613</a>)</li>
<li>Fixed the {@code STLport} internal {@code _IteWrapper::operator*()} implementation
where a stale stack location holding the dereferenced value was returned and caused
runtime crashes.
- (<a href="http://b.android.com/38630">Issue 38630</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=38630">Issue 38630</a>)</li>
<li>ARM-specific fixes:
<ul>
@@ -1028,17 +755,17 @@
<li>Fixed {@code binutils-2.21/ld.bfd} to be capable of linking object from older
binutils without {@code tag_FP_arch}, which was producing <em>assertion fail</em>
error messages in GNU Binutils.
- (<a href="http://b.android.com/35209">Issue 35209</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=35209">Issue 35209</a>)
</li>
<li>Removed <em>Unknown EABI object attribute 44</em> warning when
{@code binutils-2.19/ld} links prebuilt object by newer {@code binutils-2.21}</li>
<li>Fixed an issue in GNU {@code stdc++} compilation with both {@code -mthumb} and
{@code -march=armv7-a}, by modifying {@code make-standalone-toolchain.sh} to populate
{@code headers/libs} in sub-directory {@code armv7-a/thumb}.
- (<a href="http://b.android.com/35616">Issue 35616</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=35616">Issue 35616</a>)
</li>
<li>Fixed <em>unresolvable R_ARM_THM_CALL relocation</em> error.
- (<a href="http://b.android.com/35342">Issue 35342</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=35342">Issue 35342</a>)
</li>
<li>Fixed internal compiler error at {@code reload1.c:3633}, caused by the ARM
back-end expecting the wrong operand type when sign-extend from {@code char}.
@@ -1067,11 +794,11 @@
<li>Disabled Python support in gdb-7.x at build, otherwise the gdb-7.x configure
function may pick up whatever Python version is available on the host and build
{@code gdb} with a hard-wired dependency on a specific version of Python.
- (<a href="http://b.android.com/36120">Issue 36120</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=36120">Issue 36120</a>)
</li>
<li>Fixed {@code ndk-gdb} when {@code APP_ABI} contains {@code all} and matchs none
of the known architectures.
- (<a href="http://b.android.com/35392">Issue 35392</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=35392">Issue 35392</a>)
</li>
<li>Fixed Windows pathname support, by keeping the {@code :} character if it looks
like it could be part of a Windows path starting with a drive letter.
@@ -1082,7 +809,7 @@
</li>
<li>Added fix to only read the current {@code solibs} when the linker is consistent.
This change speeds up {@code solib} event handling.
- (<a href="http://b.android.com/37677">Issue 37677</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=37677">Issue 37677</a>)
</li>
<li>Added fix to make repeated attempts to find {@code solib} breakpoints. GDB now
retries {@code enable_break()} during every call to {@code svr4_current_sos()} until
@@ -1090,13 +817,13 @@
(<a href="https://android-review.googlesource.com/#/c/43563">Change 43563</a>)</li>
<li>Fixed an issue where {@code gdb} would not stop on breakpoints placed in
{@code dlopen-ed} libraries.
- (<a href="http://b.android.com/34856">Issue 34856</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=34856">Issue 34856</a>)
</li>
<li>Fixed {@code SIGILL} in dynamic linker when calling {@code dlopen()}, on system
where {@code /system/bin/linker} is stripped of symbols and
{@code rtld_db_dlactivity()} is implemented as {@code Thumb}, due to not preserving
{@code LSB} of {@code sym_addr}.
- (<a href="http://b.android.com/37147">Issue 37147</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=37147">Issue 37147</a>)
</li>
</ul>
</li>
@@ -1121,7 +848,7 @@
{@code __END_DECLS}.</li>
<li>Removed unimplemented functions in {@code malloc.h}.</li>
<li>Fixed {@code stdint.h} defintion of {@code uint64_t} for ANSI compilers.
- (<a href="http://b.android.com/1952">Issue 1952</a>)</li>
+ (<a href="http://code.google.com/p/android/issues/detail?id=1952">Issue 1952</a>)</li>
<li>Fixed preprocessor macros in {@code <arch>/include/machine/*}.</li>
<li>Replaced {@code link.h} for MIPS with new version supporting all platforms.</li>
<li>Removed {@code linux-unistd.h}</li>
@@ -1177,7 +904,7 @@
{@code platforms/android-[3,4,5,8]}. Those headers were incomplete, since both X86 and
MIPS ABIs are only supported at API 9 or higher.</li>
<li>Simplified c++ include path in standalone packages, as shown below.
- (<a href="http://b.android.com/35279">Issue 35279</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=35279">Issue 35279</a>)
<pre>
<path>/arm-linux-androideabi/include/c++/4.6.x-google
to:
@@ -1189,7 +916,7 @@
<li>Fixed an issue in {@code samples/san-angeles} that caused a black screen or freeze
frame on re-launch.</li>
<li>Replaced deprecated APIs in NDK samples.
- (<a href="http://b.android.com/20017">Issue 20017</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=20017">Issue 20017</a>)
<ul>
<li>{@code hello-gl2} from android-5 to android-7</li>
<li>{@code native-activity} from android-9 to android-10</li>
@@ -1469,7 +1196,7 @@
<li>Fixed a typo in GAbi++ implementation where the result of {@code
dynamic_cast<D>(b)} of base class object {@code b} to derived class {@code D} is
incorrectly adjusted in the opposite direction from the base class.
- (<a href="http://b.android.com/28721">Issue 28721</a>)
+ (<a href="http://code.google.com/p/android/issues/detail?id=28721">Issue 28721</a>)
</li>
<li>Fixed an issue in which {@code make-standalone-toolchain.sh} fails to copy
{@code libsupc++.*}.</li>
@@ -1983,7 +1710,7 @@
<li>Fixed the standalone toolchain linker warnings about missing the definition and
size for the <code>__dso_handle</code> symbol (ARM only).</li>
<li>Fixed the inclusion order of <code>$(SYSROOT)/usr/include</code> for x86 builds.
- See the <a href="http://b.android.com/18540">bug</a> for
+ See the <a href="http://code.google.com/p/android/issues/detail?id=18540">bug</a> for
more information.</li>
<li>Fixed the definitions of <code>ptrdiff_t</code> and <code>size_t</code> in
x86-specific systems when they are used with the x86 standalone toolchain.</li>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
new file mode 100644
index 0000000..12fc0ae
--- /dev/null
+++ b/docs/html/tools/support-library/features.jd
@@ -0,0 +1,249 @@
+page.title=Support Library Features
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#v4">v4 Support Library</a></li>
+ <li><a href="#v7">v7 Libraries</a>
+ <ol>
+ <li><a href="#v7-appcompat">v7 appcompat library</a></li>
+ <li><a href="#v7-gridlayout">v7 gridlayout library</a></li>
+ </ol>
+ </li>
+ <li><a href="#v13">v13 Support Library</a></li>
+ </ol>
+
+ <h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}tools/support-library/index.html#revisions">
+ Support Library Revisions</a></li>
+ <li><a href="{@docRoot}tools/support-library/setup.html">
+ Support Library Setup</a></li>
+ </ol>
+
+ </div>
+</div>
+
+<p>The Android Support Library package contains several libraries that can be included
+ in your application. Each of these libraries supports a specific range of Android platform
+ versions and set of features.</p>
+
+<p>This guide explains the important features and version support provided by the Support
+ Libraries to help you decide which of them you should include in your application. In general,
+ we recommend including the <a href="#v4">v4 support</a> and <a href="#v7-appcompat">v7
+ appcompat</a> libraries, because they support a wide range of
+ Android versions and provide APIs for recommended user interface patterns.</p>
+
+<p>In order to use any of the following libraries, you must download the library files to your
+ Android SDK installation. Follow the directions for downloading the Support Libraries in
+ <a href="{@docRoot}tools/support-library/setup.html#download">Support Library Setup</a> to
+ complete this step. You must take additional steps to include a specific Support Library in
+ your application. See the end of each library section below for important information on how to
+ include the library in your application.</p>
+
+
+<h2 id="v4">v4 Support Library</h2>
+
+<p>This library is designed to be used with Android 1.6 (API level 4) and higher. It includes the
+ largest set of APIs compared to the other libraries, including support for application components,
+ user interface features, accessibility, data handling, network connectivity, and programming
+ utilities. Here are a few of the key classes included in the v4 library:</p>
+
+<ul>
+ <li>App Components
+ <ul>
+ <li>{@link android.support.v4.app.Fragment}
+ - Adds support encapsulation of user interface and functionality with Fragments, enabling
+ applications provide layouts that adjust between small and large-screen devices.</li>
+ </ul>
+ <ul>
+ <li>{@link android.support.v4.app.NotificationCompat} - Adds support for rich notification
+ features.</li>
+ </ul>
+ <ul>
+ <li>{@link android.support.v4.content.LocalBroadcastManager} - Allows applications to easily
+ register for and receive intents within a single application without broadcasting them
+ globally.</li>
+ </ul>
+ </li>
+ <li>User Interface
+ <ul>
+ <li>{@link android.support.v4.view.ViewPager} - Adds a
+ {@link android.view.ViewGroup} that manages the layout for the
+ child views, which the user can swipe between.</li>
+ <li>{@link android.support.v4.view.PagerTitleStrip}
+ - Adds a non-interactive title strip, that can be added as a child of
+ {@link android.support.v4.view.ViewPager}.</li>
+ <li>{@link android.support.v4.view.PagerTabStrip} - Adds a
+ navigation widget for switching between paged views, that can also be used with
+ {@link android.support.v4.view.ViewPager}.</li>
+ <li>{@link android.support.v4.widget.DrawerLayout} - Adds
+ support for creating a <a href="{@docRoot}training/implementing-navigation/nav-drawer.html"
+ >Navigation Drawer</a> that can be pulled in from the edge of a window.</li>
+ <li>{@link android.support.v4.widget.SlidingPaneLayout}
+ - Adds widget for creating linked summary and detail views that
+ appropriately adapt to various screen sizes.</li>
+ </ul>
+ </li>
+ <li>Accessibility
+ <ul>
+ <li>{@link android.support.v4.widget.ExploreByTouchHelper}
+ - Adds a helper class for implementing accessibility support for custom views.</li>
+ </ul>
+ <ul>
+ <li>{@link android.support.v4.view.accessibility.AccessibilityEventCompat} - Adds support for
+ {@link android.view.accessibility.AccessibilityEvent}. For more information about implementing
+ accessibility, see <a href="{@docRoot}guide/topics/ui/accessibility/index.html"
+ >Accessibility</a>.</li>
+ </ul>
+ <ul>
+ <li>{@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat} - Adds support
+ for {@link android.view.accessibility.AccessibilityNodeInfo}.</li>
+ </ul>
+ <ul>
+ <li>{@link android.support.v4.view.accessibility.AccessibilityNodeProviderCompat} - Adds
+ support for {@link android.view.accessibility.AccessibilityNodeProvider}.</li>
+ </ul>
+ <ul>
+ <li>{@link android.support.v4.view.AccessibilityDelegateCompat} - Adds support for
+ {@link android.view.View.AccessibilityDelegate}.</li>
+ </ul>
+ </li>
+ <li>Content
+ <ul>
+ <li>{@link android.support.v4.content.Loader} - Adds support for asynchronous loading of data.
+ The library also provides concrete implementations of this class, including
+ {@link android.support.v4.content.CursorLoader} and
+ {@link android.support.v4.content.AsyncTaskLoader}.</li>
+ </ul>
+ <ul>
+ <li>{@link android.support.v4.content.FileProvider} - Adds support for sharing of private
+ files between applications.</li>
+ </ul>
+ </li>
+</ul>
+
+<p>
+ There are many other APIs included in this library. For complete, detailed information about the
+ v4 Support Library APIs, see the {@link android.support.v4.app android.support.v4} package in the
+ API reference.
+</p>
+
+<p>This library is located in the {@code <sdk>/extras/android/support/v4/} directory after
+ you download the Android Support Libraries. This library does not contain user interface
+ resources. To include it in your application project, follow the instructions for
+ <a href="{@docRoot}tools/support-library/setup.html#libs-without-res">adding libraries without
+ resources</a>.</p>
+
+<p>The Gradle build script dependency identifier for this library is as follows:</p>
+
+<pre>
+com.android.support:support-v4:18.0.+
+</pre>
+
+<p>This dependency notation specifies the release version 18.0.0 or higher.</p>
+
+
+
+<h2 id="v7">v7 Libraries</h2>
+
+<p>There are several libraries designed to be used with Android 2.1 (API level 7) and higher.
+ These libraries provide specific feature sets and can be included in your application
+ independently from each other.</p>
+
+
+<h3 id="v7-appcompat">v7 appcompat library</h3>
+
+<p>This library adds support for the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action
+ Bar</a> user interface <a href="{@docRoot}design/patterns/actionbar.html">design pattern</a>.
+</p>
+
+<p class="note"><strong>Note:</strong>
+ This library depends on the v4 Support Library. If you are using Ant or Eclipse, make sure
+ you include the v4 Support Library as part of this library's classpath.
+</p>
+
+<p>Here are a few of the key classes included in the v7 appcompat library:</p>
+
+<ul>
+ <li>{@link android.support.v7.app.ActionBar} - Provides an implementation of the action bar
+ <a href="{@docRoot}design/patterns/actionbar.html">user interface pattern</a>. For more
+ information on using the Action Bar, see the
+ <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> developer guide.
+ </li>
+ <li>{@link android.support.v7.app.ActionBarActivity} - Adds an application activity class that
+ must be used as a base class for activities that uses the Support Library action bar
+ implementation.
+ </li>
+ <li>{@link android.support.v7.widget.ShareActionProvider} - Adds support for a standardized
+ sharing action (such as email or posting to social applications) that can be included in an
+ action bar.
+ </li>
+</ul>
+
+<p>This library is located in the {@code <sdk>/extras/android/support/v7/appcompat/}
+ directory after you download the Android Support Libraries. This library contains user
+ interface resources. To include it in your application project, follow the instructions for
+ <a href="{@docRoot}tools/support-library/setup.html#libs-with-res">adding libraries with
+ resources</a>.</p>
+
+<p>The Gradle build script dependency identifier for this library is as follows:</p>
+
+<pre>
+com.android.support:appcompat-v7:18.0.+
+</pre>
+
+<p>This dependency notation specifies release version 18.0.0 or higher.</p>
+
+
+
+<h3 id="v7-gridlayout">v7 gridlayout library</h3>
+
+<p>This library adds support for the {@link android.support.v7.widget.GridLayout} class, which
+ allows you to arrange user interface elements using a grid of rectangular cells.
+ For detailed information about the v7 gridlayout library APIs, see the
+ {@link android.support.v7.widget android.support.v7.widget} package in the API reference.</p>
+
+<p>This library is located in the {@code <sdk>/extras/android/support/v7/gridlayout/}
+ directory after you download the Android Support Libraries. This library contains user
+ interface resources. To include it in your application project, follow the instructions for
+ <a href="{@docRoot}tools/support-library/setup.html#libs-with-res">adding libraries with
+ resources</a>.</p>
+
+<p>The Gradle build script dependency identifier for this library is as follows:</p>
+
+<pre>
+com.android.support:gridlayout-v7:18.0.+
+</pre>
+
+<p>This dependency notation specifies release version 18.0.0 or higher.</p>
+
+
+<h2 id="v13">v13 Support Library</h2>
+
+<p>This library is designed to be used for Android 3.2 (API level 13) and higher. It adds support
+ for the <a href="{@docRoot}guide/components/fragments.html">Fragment</a> user interface pattern
+ with the ({@link android.support.v13.app.FragmentCompat}) class and additional fragment support
+ classes For more information about fragments, see the
+ <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide. For detailed
+ information about the v13 Support Library APIs, see the {@link android.support.v13.app
+ android.support.v13} package in the API reference.
+</p>
+
+<p>This library is located in the {@code <sdk>/extras/android/support/v13/} directory after
+ you download the Android Support Libraries. This library does not contain user interface
+ resources. To include it in your application project, follow the instructions for
+ <a href="{@docRoot}tools/support-library/setup.html#libs-without-res">adding libraries without
+ resources</a>.</p>
+
+<p>The Gradle build script dependency identifier for this library is as follows:</p>
+
+<pre>
+com.android.support:support-v13:18.0.+
+</pre>
+
+<p>This dependency notation specifies the release version 18.0.0 or higher.</p>
diff --git a/docs/html/tools/extras/support-library.jd b/docs/html/tools/support-library/index.jd
similarity index 66%
rename from docs/html/tools/extras/support-library.jd
rename to docs/html/tools/support-library/index.jd
index a82a98a..420fa0f 100644
--- a/docs/html/tools/extras/support-library.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -3,52 +3,148 @@
@jd:body
<div id="qv-wrapper">
-<div id="qv">
+ <div id="qv">
-<h2>In this document</h2>
-<ol>
- <li><a href="#Notes">Revisions</a></li>
- <li><a href="#Downloading">Downloading the Support Package</a></li>
- <li><a href="#SettingUp">Setting Up a Project to Use a Library</a></li>
- <li><a href="#Using">Using the v4 Library APIs</a></li>
- <li><a href="#Docs">Reference Docs</a></li>
- <li><a href="#Samples">Samples</a></li>
-</ol>
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#overview">Overview</a></li>
+ <li><a href="#revisions">Revisions</a></li>
+ </ol>
-<h2>See also</h2>
-<ol>
- <li><a
-href="{@docRoot}training/basics/fragments/support-lib.html">Using the Support Library</a></li>
-</ol>
+ <h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}tools/support-library/features.html">
+ Support Library Features</a></li>
+ <li><a href="{@docRoot}tools/support-library/setup.html">
+ Support Library Setup </a></li>
+ </ol>
-</div>
+ </div>
</div>
-<p><em>Minimum API level supported:</em> <b>4</b></p>
+<p>The Android Support Library package is a set of code libraries that provide useful and important
+ features for Android applications in addition to the framework APIs. These libraries provide
+ backward-compatible versions of Android framework APIs as well as features that are only available
+ through the library APIs. Each Support Library is backward-compatible to a specific Android API
+ level. This design means that your applications can use the libraries' features and still be
+ compatible with devices running Android 1.6 (API level 4) and up.</p>
-<p>The Support Package includes static "support libraries" that you can add to your Android
-application in order to use APIs that are either not available for older platform versions or that
-offer "utility" APIs that aren't a part of the framework APIs. The goal is to simplify your
-development by offering more APIs that you can bundle with your application so you can
-worry less about platform versions.</p>
-
-<p class="note"><strong>Note:</strong> The Support Package includes more than one support
-library. Each one has a different <em>minimum API level</em>. For example, one library requires API
-level 4 or higher, while another requires API level 13 or higher (v13 is a superset of v4 and
-includes additional
-support classes to work with v13 APIs). The minimum version is indicated
-by the directory name, such as {@code v4/} and {@code v13/}.</p>
+<p>This guide provides information about what features are enabled by the Support Libraries,
+ how to use them in your development environment and information about library releases.</p>
-<h2 id="Notes">Revisions</h2>
+<h2 id="overview">Overview</h2>
-<p>The sections below provide notes about successive releases of
-the Support Package, as denoted by revision number.</p>
+<p>Including the Support Libraries in your Android project is considered a best practice for
+ application developers. Using the features they provide can help you improve the look of your
+ application, increase performance and broaden the reach of your application to more users.
+ If you use the Android
+ <a href="{@docRoot}tools/projects/templates.html">code template</a> tools, you will notice that
+ all the Android application templates include one or more of the Support Libraries by default.</p>
+
+<p>The Support Libraries each target a base Android API level and each provides a different set
+ of features. In order to effectively use the libraries, it is important to consider what features
+ you want to support and understand what features are supported by each library at what Android
+ API level. To get started, review the
+ <a href="{@docRoot}tools/support-library/features.html">Support Library Features</a> guide.
+ After that, go to the
+ <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a> topic to
+ learn how to incorporate the Support Libraries into your application. For more details
+ about Support Library APIs, see the {@link android.support.v4.app android.support}
+ packages in the API reference.</p>
+
+
+<h2 id="revisions">Revisions</h2>
+
+<p>This section provides details about the Support Library package releases.</p>
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
-/>Support Package, revision 13</a> <em>(May 2013)</em>
+/>Android Support Library, revision 18</a> <em>(July 2013)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+ <dl>
+ <dt>Changes for v4 support library:</dt>
+ <dd>
+ <ul>
+ <li>User interface
+ <ul>
+ <li>Added {@link android.support.v4.text.BidiFormatter} for handling
+ text strings that combine right to left and left to right-formatted text.</li>
+ <li>Modified {@link android.support.v4.view.ViewPager} to better handle cases where the
+ pager has a measured width of zero in the initial layout processing.</li>
+ <li>Modified {@link android.support.v4.widget.DrawerLayout} and
+ {@link android.support.v4.widget.SlidingPaneLayout} to not throw exceptions for
+ measurement while the project code is being edited.</li>
+ </ul>
+ </li>
+
+ <li>Accessibility
+ <ul>
+ <li>Added {@link android.support.v4.widget.ExploreByTouchHelper} to simplify the
+ implementation of accessibility for custom views.</li>
+ <li>Fixed a problem with {@link android.support.v4.view.ViewPager} incorrectly
+ populating {@link
+ android.support.v4.view.accessibility.AccessibilityEventCompat#TYPE_VIEW_SCROLLED
+ TYPE_VIEW_SCROLLED} accessibility events.</li>
+ <li>Fixed a null pointer exception in {@link android.support.v4.view.ViewPager} when
+ populating an accessibility event.</li>
+ <li>Simplified {@link android.support.v4.view.accessibility.AccessibilityNodeInfoCompat}
+ by changing {@link java.lang.CharSequence} inputs to {@link java.lang.String} objects.
+ </li>
+ <li>Deprecated an {@link android.support.v4.view.accessibility.AccessibilityRecordCompat}
+ constructor that used an {@link java.lang.Object} as input.</li>
+ </ul>
+ </li>
+
+ <li>Media
+ <ul>
+ <li>Added {@link android.support.v4.media.TransportMediator} helper class to manage
+ media transport control, such as play, pause, skip and other media actions.</li>
+ <li>Added {@link android.support.v4.hardware.display.DisplayManagerCompat} for managing
+ display output to one or more device displays.</li>
+ </ul>
+ </li>
+
+ <li>Other changes
+ <ul>
+ <li>Added {@link android.support.v4.content.WakefulBroadcastReceiver} helper class for
+ implementing a common pattern of detecting a device wakeup event and passing work off
+ to a {@link android.app.Service} while ensuring that the device does not go back to
+ sleep before the handoff is complete.</li>
+ <li>Added two new APIs,
+ {@link android.support.v4.content.AsyncTaskLoader#commitContentChanged
+ commitContentChanged()} and
+ {@link android.support.v4.content.AsyncTaskLoader#rollbackContentChanged
+ rollbackContentChanged()}, to {@link android.support.v4.content.AsyncTaskLoader} to
+ help deal with background updates for data changes that are subsequently canceled.
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </dd>
+
+ <dt>New v7 appcompat library:</dt>
+ <dd>
+ <ul>
+ <li>Added {@link android.support.v7.app.ActionBar} to allow implementation of the
+ action bar user interface <a href="{@docRoot}/design/patterns/actionbar.html">design
+ pattern</a> back to Android 2.1 (API level 7) and higher. Use of this class requires
+ that you implement your activity by extending the new
+ {@link android.support.v7.app.ActionBarActivity} class.</li>
+ </ul>
+ </dd>
+
+ </dl>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
+/>Android Support Library, revision 13</a> <em>(May 2013)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -71,8 +167,9 @@
<li>Added {@link android.support.v4.content.FileProvider} to allow sharing of private
files between applications.</li>
<li>Updated {@link android.support.v4.view.ViewPager} to throw an exception if the
- associated {@link android.support.v4.view.PagerAdapter} class is modified without a call
- to {@link android.support.v4.view.PagerAdapter#notifyDataSetChanged notifyDataSetChanged()}.
+ associated {@link android.support.v4.view.PagerAdapter} class is modified without a
+ call to {@link android.support.v4.view.PagerAdapter#notifyDataSetChanged
+ notifyDataSetChanged()}.
</li>
<li>Fixed an issue with {@link android.support.v4.view.ViewPager} children drawing sort
order.</li>
@@ -81,6 +178,15 @@
between tap timeout and long press events.</li>
</ul>
</dd>
+
+ <dt>New v7 gridlayout library:</dt>
+ <dd>
+ <ul>
+ <li>Added {@link android.support.v7.widget.GridLayout} to provide support for the
+ {@link android.widget.GridLayout} layout object.</li>
+ <li>Added {@link android.support.v7.widget.Space} which can be used to create blank areas
+ within a {@link android.support.v7.widget.GridLayout} layout object.</li>
+ </ul>
</dl>
</div>
</div>
@@ -89,7 +195,7 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 12</a> <em>(February 2013)</em>
+/>Android Support Library, revision 12</a> <em>(February 2013)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -110,10 +216,11 @@
</div>
</div>
+
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 11</a> <em>(November 2012)</em>
+/>Android Support Library, revision 11</a> <em>(November 2012)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -175,7 +282,7 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 10</a> <em>(August 2012)</em>
+/>Android Support Library, revision 10</a> <em>(August 2012)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -194,7 +301,7 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 9</a> <em>(June 2012)</em>
+/>Android Support Library, revision 9</a> <em>(June 2012)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -260,10 +367,11 @@
</div>
</div>
+
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 8</a> <em>(April 2012)</em>
+/>Android Support Library, revision 8</a> <em>(April 2012)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -282,10 +390,11 @@
</div>
</div>
+
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 7</a> <em>(March 2012)</em>
+/>Android Support Library, revision 7</a> <em>(March 2012)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -311,10 +420,11 @@
</div>
</div>
+
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 6</a> <em>(December 2011)</em>
+/>Android Support Library, revision 6</a> <em>(December 2011)</em>
</p>
<div class="toggle-content-toggleme">
@@ -367,7 +477,7 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 5</a> <em>(December 2011)</em>
+/>Android Support Library, revision 5</a> <em>(December 2011)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -426,7 +536,7 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Support Package, revision 4</a> <em>(October 2011)</em>
+/>Android Support Library, revision 4</a> <em>(October 2011)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -468,7 +578,7 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Compatibility Package, revision 3</a> <em>(July 2011)</em>
+/>Android Support Library, revision 3</a> <em>(July 2011)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -519,7 +629,7 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Compatibility Package, revision 2</a> <em>(May 2011)</em>
+/>Android Support Library, revision 2</a> <em>(May 2011)</em>
</p>
<div class="toggle-content-toggleme">
<dl>
@@ -527,7 +637,7 @@
<dd>
<ul>
<li>Support for fragment animations</li>
- <li>Fix {@code android.support.v4.app.Fragment#onActivityResult Fragment.onActivityResult()}
+ <li>Fix {@link android.support.v4.app.Fragment#onActivityResult Fragment.onActivityResult()}
bug</li>
</ul>
</dd>
@@ -539,204 +649,10 @@
<div class="toggle-content closed">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
-/>Compatibility Package, revision 1</a> <em>(March 2011)</em>
+/>Android Support Library, revision 1</a> <em>(March 2011)</em>
</p>
<div class="toggle-content-toggleme">
<p>Initial release with the v4 library.</p>
</div>
</div>
-
-
-<h2 id="Downloading">Downloading the Support Package</h2>
-
-<p>The Support Package is provided as a downloadable package from the Android SDK
-Manager. To install:</p>
-
-<ol>
- <li>Launch the Android SDK Manager.
- <p>From Eclipse, you can select <strong>Window</strong>
-> <strong>Android SDK Manager</strong>. Or, launch {@code SDK Manager.exe} from
-the {@code <sdk>/} directory (on Windows only) or {@code android} from the {@code
-<sdk>/tools/} directory.</p></li>
- <li>Expand the Android Repository, check <strong>Android Support package</strong>
-and click <strong>Install selected</strong>.</li>
- <li>Proceed to install the package.</li>
-</ol>
-
-<p>When done, all files (including source code, samples, and the JAR files) are saved
-into the <code><sdk>/extras/android/support/</code> directory. This directory contains
-each of the different support libraries, such as the library for API level 4 and up and the library
-for API level 13 and up, each named with the respective version (such as {@code v4/}).</p>
-
-
-<h2 id="SettingUp">Setting Up a Project to Use a Library</h2>
-
-<p>To add one of the libraries to your Android project:</p>
-<dl>
- <dt>
- Add the JAR file to your project.
- </dt>
- <dd>
- Copy the JAR file for the library you want to use into your Android project. To do this:
- <ul>
- <li>
- Create the directory {@code libs/} at the root of your project
- (next to {@code src/}, {@code res/}, and so forth).
- </li>
- <li>
- Locate the JAR file for the library you want to use and copy it into the
- {@code libs/} directory.
- <p>
- For example, the library that supports API level 4 and up is located at
- {@code <sdk>/extras/android/support/v4/android-support-v4.jar}.
- </p>
- </li>
- </ul>
- <p>
- Your build system may expect to find the JAR file in a directory other than
- {@code libs}. Read the documentation for your build system to learn where to put the
- JAR file.
- </p>
- </dd>
- <dt>
- If necessary, add the {@code libs/} directory to your build path.
- </dt>
- <dd>
- Read the documentation for your build system to learn how to add the JAR file to the
- build path.
- </dd>
-</dl>
-<p>
- To confirm that you've added the JAR file to the correct directory and added it to the build
- path:
-</p>
-<ol>
- <li>
- Edit one of your source files to add an {@code import} statement that imports a
- class from the {@code android.support.*} package.
- </li>
- <li>
- Build your app. The code should compile cleanly.
- </li>
- <li>
- As a double-check, run your app. It should run correctly, without any runtime exceptions
- indicating that the class in {@code android.support.*} can't be found.
- </li>
-</ol>
-<p>Your application is now ready to use the library APIs. All the
-provided APIs are available in the {@code android.support} package (for
-example, {@code android.support.v4}).</p>
-
-<p class="note"><strong>Tip:</strong> To see the library APIs in action, take a look at the sample
-apps in {@code <sdk>/extras/android/support/<version>/samples/}.</p>
-
-<p class="warning"><strong>Warning:</strong> Be certain that you not confuse the standard
-{@code android} packages with those in {@code android.support} library. Some code completion tools
-might
-get this wrong, especially if you're building against recent versions of the platform. To be safe,
-keep your build target set to the same version as you have defined for your <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
-and double check the import statements for classes that also exist in the support library, such as
-{@code SimpleCursorAdapter}.</p>
-
-
-<h2 id="Using">Using the v4 Library APIs</h2>
-
-<p>The support library for v4 provides access to several classes introduced with Android 3.0 and
-beyond, plus some updated version of existing classes, and even some APIs that currently don't
-exist in the Android platform. Some of the most useful and notable classes that have
-counterparts in the v4 support library are:</p>
-
-<ul>
- <li>{@link android.app.Fragment}</li>
- <li>{@link android.app.FragmentManager}</li>
- <li>{@link android.app.FragmentTransaction}</li>
- <li>{@link android.app.ListFragment}</li>
- <li>{@link android.app.DialogFragment}</li>
- <li>{@link android.app.LoaderManager}</li>
- <li>{@link android.content.Loader}</li>
- <li>{@link android.content.AsyncTaskLoader}</li>
- <li>{@link android.content.CursorLoader}</li>
-</ul>
-
-<p>For each of the classes above (and others not listed), the APIs work almost exactly the same
-as the counterparts in the latest Android platform. Thus, you can usually refer to
-the online documentation for information about the supported APIs. There are some
-differences, however. Most notably:</p>
-
-<ul>
- <li>When creating an activity to use fragments, you must declare your activity to extend the
-{@link android.support.v4.app.FragmentActivity} class (instead of the traditional
-{@link android.app.Activity} class).</li>
- <li>To manage your fragments and loaders, you must use the methods
- {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager
- FragmentActivity.getSupportFragmentManager()} and
- {@link android.support.v4.app.FragmentActivity#getSupportLoaderManager
- FragmentActivity.getSupportLoaderManager()} (instead of the
- {@link android.app.Activity#getFragmentManager()} and
- {@link android.app.Activity#getLoaderManager()} methods).</li>
- <li>The {@link android.app.ActionBar} is <strong>not supported</strong> by the library.
-However, when creating your <a href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options
-Menu</a>, you can declare which items should be added to the Action Bar when it's available (on
-Android 3.0 or later). You can do so with the
-{@link android.support.v4.view.MenuCompat#setShowAsAction MenuCompat.setShowAsAction()} method, for
-example:
-<pre>
-public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.options, menu);
- MenuCompat.setShowAsAction(menu.findItem(R.id.action_search), 1);
- return true;
-}
-</pre>
-<p>Also see the <a href="{@docRoot}resources/samples/ActionBarCompat/index.html">Action Bar
-Compatibility</a> sample for a demonstration of how to use {@link android.app.ActionBar} on Android
-3.0+ and also support action bar functionality on older versions.</p>
-</li>
-</ul>
-
-<div class="note"><p><strong>Tip:</strong> To enable the Holographic theme on devices
-running Android 3.0 or higher, declare in your manifest file that your application targets
-API level 11, for example:</p>
-<pre>
-<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="11" />
-</pre>
-<p>This way, your application automatically receives the Holographic theme and the Action Bar for
-each activity when running on Android 3.0 and higher.</p>
-</div>
-
-<p>For more information about how you can optimize your application for the latest
-Android-powered devices, read <a href="{@docRoot}guide/practices/tablets-and-handsets.html"
->Supporting Tablets and Handsets</a>.</p>
-
-
-<h2 id="Docs">Reference Docs</h2>
-
-<p>The reference documentation for the Support Packages is included as part of the Android
-online developer documentation:</p>
-
-<ul>
- <li><a href="{@docRoot}reference/android/support/v4/app/package-summary.html">Support Package
- API 4 Reference</a></li>
- <li><a href="{@docRoot}reference/android/support/v13/app/package-summary.html">Support Package
- API 13 Reference</a></li>
-</ul>
-
-
-<h2 id="Samples">Samples</h2>
-
-<p>If you want to see some code that uses the support libraries, samples are included with the
-Support Package, inside each support library directory, for example; {@code
-<sdk>/extras/android/support/v4/samples/}. You can also view these samples as part of the
-Android online developer documentation:</p>
-
-<ul>
- <li><a href="{@docRoot}resources/samples/Support4Demos/index.html">Support API 4 Demos</a></li>
- <li><a href="{@docRoot}resources/samples/Support13Demos/index.html">Support API 13 Demos</a></li>
-</ul>
-
-<p>Additionally, the <a href="http://code.google.com/p/iosched/">Google I/O App</a> is a complete
-application that uses the v4 support library to provide a single APK for both handsets and tablets
-and also demonstrates some of Android's best practices in Android UI design.</p>
-
diff --git a/docs/html/tools/support-library/setup.jd b/docs/html/tools/support-library/setup.jd
new file mode 100644
index 0000000..6cca897
--- /dev/null
+++ b/docs/html/tools/support-library/setup.jd
@@ -0,0 +1,308 @@
+page.title=Support Library Setup
+
+@jd:body
+
+
+<div id="qv-wrapper">
+ <div id="qv">
+
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#download">Downloading the Support Library</a></li>
+ <li><a href="#choosing">Choosing Support Libraries</a></li>
+ <li><a href="add-library">Adding Support Libraries</a>
+ <ol>
+ <li><a href="#libs-without-res">Adding libraries without resources</a></li>
+ <li><a href="#libs-with-res">Adding libraries with resources</a></li>
+ </ol>
+ </li>
+ <li><a href="#using-apis">Using Support Library APIs</a>
+ <ol>
+ <li><a href="#manifest">Manifest Declaration Changes</a></li>
+ </ol>
+ </li>
+ <li><a href="#samples">Code Samples</a></li>
+ </ol>
+
+ <h2>See also</h2>
+ <ol>
+ <li><a href="{@docRoot}tools/support-library/index.html#revisions">
+ Support Library Revisions</a></li>
+ <li><a href="{@docRoot}tools/support-library/features.html">
+ Support Library Features</a></li>
+ </ol>
+
+ </div>
+</div>
+
+<p>How you setup the Android Support Libraries in your development project depends on what features
+ you want to use and what range of Android platform versions you want to support with your
+ application.</p>
+
+<p>This document guides you through downloading the Support Library package and adding libraries
+ to your development environment.</p>
+
+
+<h2 id="download">Downloading the Support Libraries</h2>
+
+<p>The Android Support Library package is provided as a supplemental download to the Android SDK
+ and is available through the Android
+ <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>. Follow the
+ instructions below to obtain the Support Library files.
+</p>
+
+<p>To download the Support Library through the SDK Manager:</p>
+
+<ol>
+ <li>Start the Android <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</li>
+ <li>In the SDK Manager window, scroll to the end of the <em>Packages</em> list,
+ find the <em>Extras</em> folder and, if necessary, expand to show its contents.</li>
+ <li>Select the <strong>Android Support Library</strong> item.
+ <p class="note">
+ <strong>Note:</strong> If you're developing with Android Studio, select and install the
+ <strong>Android Support Repository</strong> item instead.
+ </p>
+ </li>
+ <li>Click the <strong>Install packages...</strong> button.</li>
+</ol>
+
+<img src="{@docRoot}images/tools/sdk-manager-support-libs.png" width="525" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> The Android SDK Manager with the
+Android Support Library selected.</p>
+
+<p>After downloading, the tool installs the Support Library files to your existing Android SDK
+ directory. The library files are located in the following subdirectory of your SDK:
+ {@code <sdk>/extras/android/support/} directory.</p>
+
+
+<h2 id="choosing">Choosing Support Libraries</h2>
+
+<p>Before adding a Support Library to your application, decide what features you want to include
+ and the lowest Android versions you want to support. For more information on the features
+ provided by the different libraries, see
+ <a href="{@docRoot}tools/support-library/features.html">Support Library Features</a>.</p>
+
+
+<h2 id="add-library">Adding Support Libraries</h2>
+
+<p>In order to use a Support Library, you must modify your application's project's
+ classpath dependencies within your development environment. You must perform this procedure for
+ each Support Library you want to use.</p>
+
+<p>Some Support Libraries contain resources beyond compiled code classes, such as images or XML
+ files. For example, the <a href="tools/support-library/features.html#v7-appcompat">v7
+ appcompat</a> and <a href="tools/support-library/features.html#v7-gridlayout">v7 gridlayout</a>
+ libraries include resources.</p>
+
+<p>If you are not sure if a library contains resources, check the
+ <a href="{@docRoot}tools/support-library/features.html">Support Library Features</a> page.
+ The following sections describe how to add a Support Library with or without resources to your
+ application project. </p>
+
+
+<h3 id="libs-without-res">Adding libraries without resources</h3>
+
+<p>To add a Support Library without resources to your application project:</p>
+
+<div class="toggle-content closed">
+<p style="margin-top:5px"><a href="#" onclick="return toggleContent(this)">
+ <img src="/assets/images/triangle-closed.png" class="toggle-content-img" alt=""
+ />Using Eclipse</a></p>
+
+ <div class="toggle-content-toggleme">
+ <ol>
+ <li>Make sure you have downloaded the <strong>Android Support Library</strong>
+ using the <a href="#download">SDK Manager</a>.</li>
+ <li>Create a {@code libs/} directory in the root of your application project.</li>
+ <li>Copy the JAR file from your Android SDK installation directory (e.g.,
+ {@code <sdk>/extras/android/support/v4/android-support-v4.jar}) into your
+ application's project {@code libs/} directory.
+ <li>Right click the JAR file and select <strong>Build Path > Add to Build Path</strong>.
+ </li>
+ </ol>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+<p style="margin-top:5px"><a href="#" onclick="return toggleContent(this)">
+ <img src="/assets/images/triangle-closed.png" class="toggle-content-img" alt=""
+ />Using Android Studio</a></p>
+
+ <div class="toggle-content-toggleme">
+ <ol>
+ <li>Make sure you have downloaded the <strong>Android Support Repository</strong>
+ using the <a href="#download">SDK Manager</a>.</li>
+ <li>Open the {@code build.gradle} file for your application.</li>
+ <li>Add the support library to the {@code dependencies} section. For example, to add the v4
+ support library, add the following lines:
+<pre>
+dependencies {
+ ...
+ <b>compile "com.android.support:support-v4:18.0.+"</b>
+}
+</pre>
+ </li>
+ </ol>
+ </div>
+</div>
+
+
+<h3 id="libs-with-res">Adding libraries with resources</h3>
+
+<p>To add a Support Library with resources to your application project:</p>
+
+<div class="toggle-content closed">
+ <p style="margin-top:5px"><a href="#" onclick="return toggleContent(this)">
+ <img src="/assets/images/triangle-closed.png" class="toggle-content-img" alt=""
+ />Using Eclipse</a></p>
+ <div class="toggle-content-toggleme">
+
+<p>Create a <a href="{@docRoot}tools/projects/index.html#LibraryProjects">library
+project</a> based on the support library code:</p>
+
+<ol>
+ <li>Make sure you have downloaded the <strong>Android Support Library</strong>
+ using the <a href="#download">SDK Manager</a>.</li>
+ <li>Create a library project and ensure the required JAR files are included in the project's
+ build path:
+ <ol>
+ <li>Select <strong>File > Import</strong>.</li>
+ <li>Select <strong>Existing Android Code Into Workspace</strong> and click
+ <strong>Next</strong>.</li>
+ <li>Browse to the SDK installation directory and then to the Support Library folder.
+ For example, if you are adding the {@code appcompat} project, browse to
+ <code><sdk>/extras/android/support/v7/appcompat/</code>.</li>
+ <li>Click <strong>Finish</strong> to import the project. For the v7 appcompat project, you
+ should now see a new project titled <em>android-support-v7-appcompat</em>.</li>
+ <li>In the new library project, expand the {@code libs/} folder, right-click each {@code .jar}
+ file and select <strong>Build Path > Add to Build Path</strong>. For example, when
+ creating the the v7 appcompat project, add both the {@code android-support-v4.jar} and
+ {@code android-support-v7-appcompat.jar} files to the build path.</li>
+ <li>Right-click the project and select <strong>Build Path > Configure Build Path</strong>.
+ </li>
+ <li>In the <strong>Order and Export</strong> tab, check the <code>.jar</code> files you just
+ added to the build path, so they are available to projects that depend on this library
+ project. For example, the {@code appcompat} project requires you to export both the
+ {@code android-support-v4.jar} and {@code android-support-v7-appcompat.jar} files.</li>
+ <li>Uncheck <strong>Android Dependencies</strong>.</li>
+ <li>Click <strong>OK</strong> to complete the changes.</li>
+ </ol>
+ </li>
+</ol>
+
+<p>You now have a library project for your selected Support Library that you can use with one or
+ more application projects.</p>
+
+<p>Add the library to your application project:</p>
+ <ol>
+ <li>In the Project Explorer, right-click your project and select <strong>Properties</strong>.
+ <li>In the Library pane, click <strong>Add</strong>.
+ <li>Select the library project and click <strong>OK</strong>. For example, the
+ {@code appcompat} project should be listed as <strong>android-support-v7-appcompat</strong>.
+ </li>
+ <li>In the properties window, click <strong>OK</strong>.
+ </ol>
+
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+<p style="margin-top:5px"><a href="#" onclick="return toggleContent(this)">
+ <img src="/assets/images/triangle-closed.png" class="toggle-content-img" alt=""
+ />Using Android Studio</a></p>
+
+ <div class="toggle-content-toggleme">
+ <ol>
+ <li>Make sure you have downloaded the <strong>Android Support Repository</strong>
+ using the <a href="#download">SDK Manager</a>.</li>
+ <li>Open the {@code build.gradle} file for your application.</li>
+ <li>Add the support library feature project identifier to the {@code dependencies} section.
+ For example, to include the {@code appcompat} project add
+ {@code compile "com.android.support:appcompat-v7:18.0.+"} to the dependencies section, as
+ shown in the following example:
+<pre>
+dependencies {
+ ...
+ <b>compile "com.android.support:appcompat-v7:18.0.+"</b>
+}
+</pre>
+ </li>
+ </ol>
+ </div>
+</div>
+
+
+<h2 id="using-apis">Using Support Library APIs</h2>
+
+<p>Support Library classes that provide support for existing framework APIs typically have the
+ same name as framework class but are located in the <code>android.support</code> class packages,
+ or have a <code>*Compat</code> suffix.</p>
+
+<div class="caution">
+ <p><strong>Caution:</strong> When using classes from the Support Library, be certain you import
+ the class from the appropriate package. For example, when applying the {@code ActionBar}
+ class:</p>
+ <ul>
+ <li>{@code android.support.v7.app.ActionBar} when using the Support Library.</li>
+ <li>{@code android.app.ActionBar} when developing only for API level 11 or higher.</li>
+ </ul>
+</div>
+
+<p class="note">
+ <strong>Note:</strong> After including the Support Library in your application project, we
+ strongly recommend using the
+ <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool to prepare your application APK
+ for release. In addition to protecting your source code, the ProGuard tool also removes unused
+ classes from any libraries you include in your application, which keeps the download size of
+ your application as small as possible. For more information, see
+ <a href="{@docRoot}tools/help/proguard.html">ProGuard</a>.
+</p>
+
+<p>Further guidance for using some Support Library features is provided in the Android developer
+ <a href="{@docRoot}training/index.html">training classes</a>,
+ <a href="{@docRoot}guide/components/index.html">guides</a>
+ and samples. For more information about the individual Support Library classes and methods, see
+ the {@link android.support.v4.app android.support} packages in the API reference.
+</p>
+
+
+<h3 id="manifest">Manifest Declaration Changes</h3>
+
+<p>If you are increasing the backward compatibility of your existing application to an earlier
+ version of the Android API with the Support Library, make sure to update your application's
+ manifest. Specifically, you should update the <code>android:minSdkVersion</code>
+ element of the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">
+ <code><uses-sdk></code></a> tag in the manifest to the new, lower version number, as
+ shown below:</p>
+
+<pre>
+ <uses-sdk
+ android:minSdkVersion="<b>7</b>"
+ android:targetSdkVersion="17" />
+</pre>
+
+<p>This change tells Google Play that your application can be installed on devices with Android
+ 2.1 (API level 7) and higher.</p>
+
+<p class="note">
+ <strong>Note:</strong> If you are including the v4 support and v7 appcompat libraries in your
+ application, you should specify a minimum SDK version of <code>"7"</code> (and not
+ <code>"4"</code>). The highest support library level you include in your application determines
+ the lowest API version in which it can operate.
+</p>
+
+
+<h2 id="samples">Code Samples</h2>
+
+<p>Each Support Library includes code samples to help you get started using the support
+APIs. The code is included in the download from the SDK Manager and is placed inside the Android
+SDK installation directory, as listed below:</p>
+
+<ul>
+ <li>4v Samples: {@code <sdk>/extras/android/support/samples/Support4Demos/}</li>
+ <li>7v Samples: {@code <sdk>/extras/android/support/samples/Support7Demos/}</li>
+ <li>13v Samples: {@code <sdk>/extras/android/support/samples/Support13Demos/}</li>
+ <li>App Navigation: {@code <sdk>/extras/android/support/samples/SupportAppNavigation/}</li>
+</ul>
+
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index c555f98..8ad61ec 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -56,7 +56,13 @@
<li><a href="<?cs var:toroot ?>tools/devices/emulator.html"><span class="en">Using the Emulator</span></a></li>
</ul>
</li>
- <li><a href="<?cs var:toroot ?>tools/device.html"><span class="en">Using Hardware Devices</span></a></li>
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/device.html"><span class="en">Using Hardware Devices</span></a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>tools/extras/oem-usb.html"><span
+ class="en">USB Drivers</span></a></li>
+ </ul>
+ </li>
<li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot ?>tools/projects/index.html"><span class="en">Setting Up Projects</span></a></div>
<ul>
@@ -144,8 +150,18 @@
<li><a href="<?cs var:toroot ?>tools/publishing/app-signing.html"><span class="en">Signing Your Apps</span></a></li>
</ul>
</li>
-</ul>
-</li>
+ </ul>
+ </li>
+
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/support-library/index.html"><span
+class="en">Support Library</span></a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>tools/support-library/features.html">Features</a></li>
+ <li><a href="<?cs var:toroot ?>tools/support-library/setup.html">Setup</a></li>
+ </ul>
+ </li>
+
<li class="nav-section">
<div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/index.html"><span
class="en">Tools Help</span></a></div>
@@ -223,19 +239,6 @@
<li class="nav-section">
- <div class="nav-section-header"><a href="<?cs var:toroot
-?>tools/extras/index.html"><span class="en">Extras</span></a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>tools/extras/support-library.html"><span class="en">Support
-Library</span></a></li>
- <li><a href="<?cs var:toroot ?>tools/extras/oem-usb.html"><span
-class="en">USB Drivers</span></a>
- </li>
- </ul>
- </li>
-
-
- <li class="nav-section">
<div class="nav-section-header empty"><a href="<?cs var:toroot
?>tools/samples/index.html"><span class="en">Samples</span></a></div>
</li>
diff --git a/docs/html/training/animation/screen-slide.jd b/docs/html/training/animation/screen-slide.jd
index 716805e..07d779f 100644
--- a/docs/html/training/animation/screen-slide.jd
+++ b/docs/html/training/animation/screen-slide.jd
@@ -28,7 +28,7 @@
Screen slides are transitions between one entire screen to another and are common with UIs
like setup wizards or slideshows. This lesson shows you how to do screen slides with
a {@link android.support.v4.view.ViewPager} provided by the <a href=
- "{@docRoot}tools/extras/support-library.html">support library</a>.
+ "{@docRoot}tools/support-library/index.html">support library</a>.
{@link android.support.v4.view.ViewPager}s can animate screen slides
automatically. Here's what a screen slide looks like that transitions from
one screen of content to the next:
diff --git a/docs/html/training/backward-compatible-ui/index.jd b/docs/html/training/backward-compatible-ui/index.jd
index 82087a6..4baa55c 100644
--- a/docs/html/training/backward-compatible-ui/index.jd
+++ b/docs/html/training/backward-compatible-ui/index.jd
@@ -13,7 +13,7 @@
<ul>
<li>API level 5</li>
- <li><a href="{@docRoot}tools/extras/support-library.html">The Android Support Package</a></li>
+ <li><a href="{@docRoot}tools/support-library/index.html">The Android Support Package</a></li>
</ul>
<h2>You should also read</h2>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 65f22901..6f7fa5d 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -350,7 +350,7 @@
href="{@docRoot}design/patterns/navigation.html">Up navigation</a> on
Android 4.1 (API level 16) and higher. You can provide the same navigation behaviors for
older versions of Android by using the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> and adding
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a> and adding
the <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code
<meta-data>}</a> element as shown here.</p>
@@ -361,7 +361,7 @@
When using the templates in Eclipse, the Support Library is automatically added to your app project
(you can see the library's JAR file listed under <em>Android Dependencies</em>). If you're not using
Eclipse, you need to manually add the library to your project—follow the guide for <a
-href="{@docRoot}tools/extras/support-library.html#SettingUp">setting up the Support Library</a>
+href="{@docRoot}tools/support-library/setup.html">setting up the Support Library</a>
then return here.</p>
<p>If you're developing with Eclipse, you can run the app now, but not much happens.
diff --git a/docs/html/training/basics/fragments/support-lib.jd b/docs/html/training/basics/fragments/support-lib.jd
index b097de1..d949267 100644
--- a/docs/html/training/basics/fragments/support-lib.jd
+++ b/docs/html/training/basics/fragments/support-lib.jd
@@ -14,12 +14,12 @@
</ol>
<h2>You should also read</h2>
<ul>
- <li><a href="{@docRoot}tools/extras/support-library.html">Support Library</a></li>
+ <li><a href="{@docRoot}tools/support-library/index.html">Support Library</a></li>
</ul>
</div>
</div>
-<p>The Android <a href="{@docRoot}tools/extras/support-library.html">Support Library</a> provides a JAR
+<p>The Android <a href="{@docRoot}tools/support-library/index.html">Support Library</a> provides a JAR
file with an API library that allows you to use some of the more recent Android APIs in your app
while running on earlier versions of Android. For instance, the Support Library provides a version
of the {@link android.app.Fragment} APIs that you can use on Android 1.6 (API level 4) and
diff --git a/docs/html/training/basics/supporting-devices/platforms.jd b/docs/html/training/basics/supporting-devices/platforms.jd
index 04872a3..c38101a 100644
--- a/docs/html/training/basics/supporting-devices/platforms.jd
+++ b/docs/html/training/basics/supporting-devices/platforms.jd
@@ -23,7 +23,7 @@
<ul>
<li><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API Levels</a></li>
<li><a
-href="{@docRoot}tools/extras/support-library.html">Android Support Library</a></li>
+href="{@docRoot}tools/support-library/index.html">Android Support Library</a></li>
</ul>
</div>
</div>
@@ -42,7 +42,7 @@
<p class="note"><strong>Tip:</strong> In order to provide the best features and
functionality across several Android versions, you should use the <a
-href="{@docRoot}tools/extras/support-library.html">Android Support Library</a> in your app,
+href="{@docRoot}tools/support-library/index.html">Android Support Library</a> in your app,
which allows you to use several recent platform APIs on older versions.</p>
diff --git a/docs/html/training/design-navigation/wireframing.jd b/docs/html/training/design-navigation/wireframing.jd
index 42f892d..1801f91 100644
--- a/docs/html/training/design-navigation/wireframing.jd
+++ b/docs/html/training/design-navigation/wireframing.jd
@@ -121,5 +121,5 @@
<li><a href="{@docRoot}guide/topics/ui/index.html">Developer's Guide: User Interface</a>: learn how to implement your user interface designs using the Android SDK.</li>
<li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>: implement tabs, up navigation, on-screen actions, etc.
<li><a href="{@docRoot}guide/components/fragments.html">Fragments</a>: implement re-usable, multi-pane layouts
- <li><a href="{@docRoot}tools/extras/support-library.html">Support Library</a>: implement horizontal paging (swipe views) using <code>ViewPager</code></li>
+ <li><a href="{@docRoot}tools/support-library/index.html">Support Library</a>: implement horizontal paging (swipe views) using <code>ViewPager</code></li>
</ul>
diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd
index 857edee..1f44fa8 100644
--- a/docs/html/training/displaying-bitmaps/index.jd
+++ b/docs/html/training/displaying-bitmaps/index.jd
@@ -12,7 +12,7 @@
<h2>Dependencies and prerequisites</h2>
<ul>
<li>Android 2.1 (API Level 7) or higher</li>
- <li><a href="{@docRoot}tools/extras/support-library.html">Support Library</a></li>
+ <li><a href="{@docRoot}tools/support-library/index.html">Support Library</a></li>
</ul>
<h2>Try it out</h2>
diff --git a/docs/html/training/gestures/detector.jd b/docs/html/training/gestures/detector.jd
index 65ddb1b..a8e0fdb 100644
--- a/docs/html/training/gestures/detector.jd
+++ b/docs/html/training/gestures/detector.jd
@@ -58,7 +58,7 @@
<p>The examples in this lesson use the {@link android.support.v4.view.GestureDetectorCompat}
and {@link android.support.v4.view.MotionEventCompat} classes. These classes are in the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. You should use
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a>. You should use
Support Library classes where possible to provide compatibility with devices
running Android 1.6 and higher. Note that {@link android.support.v4.view.MotionEventCompat} is <em>not</em> a
replacement for the {@link android.view.MotionEvent} class. Rather, it provides static utility
diff --git a/docs/html/training/gestures/movement.jd b/docs/html/training/gestures/movement.jd
index fdc1ea4..136b37a 100644
--- a/docs/html/training/gestures/movement.jd
+++ b/docs/html/training/gestures/movement.jd
@@ -91,7 +91,7 @@
whether the gesture occurred. To make velocity calculation easier, Android
provides the {@link android.view.VelocityTracker} class and the
{@link android.support.v4.view.VelocityTrackerCompat} class in the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a>.
{@link
android.view.VelocityTracker} helps you track the velocity of touch events. This
is useful for gestures in which velocity is part of the criteria for the
diff --git a/docs/html/training/gestures/multi.jd b/docs/html/training/gestures/multi.jd
index 6a0df11..5840482 100644
--- a/docs/html/training/gestures/multi.jd
+++ b/docs/html/training/gestures/multi.jd
@@ -123,7 +123,7 @@
<p class="note"><strong>Note:</strong> This example uses the
{@link android.support.v4.view.MotionEventCompat}
class. This class is in the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. You should use
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a>. You should use
{@link android.support.v4.view.MotionEventCompat} to provide the best support for a wide range of
platforms. Note that {@link android.support.v4.view.MotionEventCompat} is <em>not</em> a
replacement for the {@link android.view.MotionEvent} class. Rather, it provides static utility
diff --git a/docs/html/training/implementing-navigation/ancestral.jd b/docs/html/training/implementing-navigation/ancestral.jd
index c3c7ef8..12d5005 100644
--- a/docs/html/training/implementing-navigation/ancestral.jd
+++ b/docs/html/training/implementing-navigation/ancestral.jd
@@ -69,7 +69,7 @@
element.</p>
<p>If your app supports Android 4.0 and lower, include the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> with your app and
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a> with your app and
add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
element inside the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
<activity>}</a>. Then specify the parent activity as the value
diff --git a/docs/html/training/implementing-navigation/index.jd b/docs/html/training/implementing-navigation/index.jd
index 519f6bb..5b65716 100644
--- a/docs/html/training/implementing-navigation/index.jd
+++ b/docs/html/training/implementing-navigation/index.jd
@@ -13,7 +13,7 @@
<ul>
<li>Android 2.2 or higher</li>
<li>Understanding of fragments and Android layouts</li>
- <li><a href="{@docRoot}tools/extras/support-library.html">Android Support Library</a></li>
+ <li><a href="{@docRoot}tools/support-library/index.html">Android Support Library</a></li>
<li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li>
</ul>
@@ -46,7 +46,7 @@
understand how to provide proper <em>Up</em> and <em>Back</em> navigation.</p>
<p class="note"><strong>Note:</strong> Several elements of this class require the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> APIs.
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a> APIs.
If you have not used the Support Library before, follow the lesson about <a
href="{@docRoot}training/basics/fragments/support-lib.html">Using the Support Library</a>
to get your project set up.</p>
diff --git a/docs/html/training/implementing-navigation/lateral.jd b/docs/html/training/implementing-navigation/lateral.jd
index b314497..97e0398 100644
--- a/docs/html/training/implementing-navigation/lateral.jd
+++ b/docs/html/training/implementing-navigation/lateral.jd
@@ -57,7 +57,7 @@
<p>You can create swipe views in your app using the {@link android.support.v4.view.ViewPager}
widget, available in the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. The
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a>. The
{@link android.support.v4.view.ViewPager} is a layout widget in which each child view is
a separate page (a separate tab) in the layout.</p>
diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd
index 38b73454..2b5e4f8 100644
--- a/docs/html/training/implementing-navigation/nav-drawer.jd
+++ b/docs/html/training/implementing-navigation/nav-drawer.jd
@@ -43,7 +43,7 @@
<p>This lesson describes how to implement a navigation drawer using the
{@link android.support.v4.widget.DrawerLayout} APIs available in the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.</p>
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a>.</p>
<div class="note design">
<p><strong>Navigation Drawer Design</strong></p>
diff --git a/docs/html/training/implementing-navigation/temporal.jd b/docs/html/training/implementing-navigation/temporal.jd
index 0719ba6..3abab53 100644
--- a/docs/html/training/implementing-navigation/temporal.jd
+++ b/docs/html/training/implementing-navigation/temporal.jd
@@ -85,7 +85,7 @@
information.</p>
<p>If your app supports Android 4.0 and lower, include the
-<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> with your app and
+<a href="{@docRoot}tools/support-library/index.html">Support Library</a> with your app and
add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
element inside the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
<activity>}</a>. Then specify the parent activity as the value
diff --git a/docs/html/training/multiscreen/index.jd b/docs/html/training/multiscreen/index.jd
index d09540e..2d34b28 100644
--- a/docs/html/training/multiscreen/index.jd
+++ b/docs/html/training/multiscreen/index.jd
@@ -19,7 +19,7 @@
<li>Experience building an Android <a
href="http://developer.android.com/guide/topics/ui/index.html"> User Interface</a></li>
<li>Several features require the use of the <a
-href="{@docRoot}tools/extras/support-library.html">support library</a></li>
+href="{@docRoot}tools/support-library/index.html">support library</a></li>
</ul>
<h2>You should also read</h2>
@@ -58,7 +58,7 @@
of reusable code for your own application.</p>
<p class="note"><strong>Note:</strong> This class and the associated sample use the <a
-href="{@docRoot}tools/extras/support-library.html">support library</a> in order to use the {@link
+href="{@docRoot}tools/support-library/index.html">support library</a> in order to use the {@link
android.app.Fragment} APIs on versions lower than Android 3.0. You must download and add the
library to your application in order to use all APIs in this class.</p>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index ad5bfc8..55664fd 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -203,10 +203,10 @@
throw new IllegalArgumentException("width and height must be > 0");
}
if (!isMutable()) {
- throw new IllegalArgumentException("only mutable bitmaps may be reconfigured");
+ throw new IllegalStateException("only mutable bitmaps may be reconfigured");
}
if (mBuffer == null) {
- throw new IllegalArgumentException("only non-inPurgeable bitmaps may be reconfigured");
+ throw new IllegalStateException("only non-purgeable bitmaps may be reconfigured");
}
nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length);
diff --git a/graphics/java/android/renderscript/package.html b/graphics/java/android/renderscript/package.html
index a844956..eb178c1 100644
--- a/graphics/java/android/renderscript/package.html
+++ b/graphics/java/android/renderscript/package.html
@@ -2,11 +2,6 @@
<BODY>
<p>RenderScript provides support for high-performance computation across heterogeneous processors.</p>
-<p>This package is for the latest native version of RenderScript included on
-Android devices. Developers interested in running RenderScript on any Android
-device running {@link android.os.Build.VERSION_CODES#GINGERBREAD} or newer
-should see the {@link android.support.v8.renderscript} package.
-
<p>For more information, see the
<a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
{@more}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 1e46f0a..be7c3b8 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -132,11 +132,7 @@
/**
* The audio channel mask
*/
- private int mChannels = AudioFormat.CHANNEL_IN_MONO;
- /**
- * The current audio channel configuration
- */
- private int mChannelConfiguration = AudioFormat.CHANNEL_IN_MONO;
+ private int mChannelMask;
/**
* The encoding of the audio samples.
* @see AudioFormat#ENCODING_PCM_8BIT
@@ -232,7 +228,7 @@
//TODO: update native initialization when information about hardware init failure
// due to capture device already open is available.
int initResult = native_setup( new WeakReference<AudioRecord>(this),
- mRecordSource, mSampleRate, mChannels, mAudioFormat, mNativeBufferSizeInBytes,
+ mRecordSource, mSampleRate, mChannelMask, mAudioFormat, mNativeBufferSizeInBytes,
session);
if (initResult != SUCCESS) {
loge("Error code "+initResult+" when initializing native AudioRecord object.");
@@ -250,7 +246,7 @@
// postconditions:
// mRecordSource is valid
// mChannelCount is valid
- // mChannels is valid
+ // mChannelMask is valid
// mAudioFormat is valid
// mSampleRate is valid
private void audioParamCheck(int audioSource, int sampleRateInHz,
@@ -276,28 +272,25 @@
//--------------
// channel config
- mChannelConfiguration = channelConfig;
-
switch (channelConfig) {
case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
case AudioFormat.CHANNEL_IN_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
mChannelCount = 1;
- mChannels = AudioFormat.CHANNEL_IN_MONO;
+ mChannelMask = AudioFormat.CHANNEL_IN_MONO;
break;
case AudioFormat.CHANNEL_IN_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
mChannelCount = 2;
- mChannels = AudioFormat.CHANNEL_IN_STEREO;
+ mChannelMask = AudioFormat.CHANNEL_IN_STEREO;
break;
case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
mChannelCount = 2;
- mChannels = channelConfig;
+ mChannelMask = channelConfig;
break;
default:
mChannelCount = 0;
- mChannels = AudioFormat.CHANNEL_INVALID;
- mChannelConfiguration = AudioFormat.CHANNEL_INVALID;
+ mChannelMask = AudioFormat.CHANNEL_INVALID;
throw (new IllegalArgumentException("Unsupported channel configuration."));
}
@@ -393,7 +386,7 @@
* and {@link AudioFormat#CHANNEL_IN_STEREO}.
*/
public int getChannelConfiguration() {
- return mChannelConfiguration;
+ return mChannelMask;
}
/**
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index e56baef..cc60d17 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -66,6 +66,11 @@
/** Debug volumes */
protected static final boolean DEBUG_VOL = false;
+ /**
+ * Used to indicate no audio focus has been gained or lost.
+ */
+ private static final int AUDIOFOCUS_NONE = 0;
+
/** Used to alter media button redirection when the phone is ringing. */
private boolean mIsRinging = false;
@@ -267,15 +272,15 @@
synchronized(mAudioFocusLock) {
if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
// notify the current focus owner it lost focus after removing it from stack
- FocusStackEntry focusOwner = mFocusStack.pop();
+ final FocusStackEntry exFocusOwner = mFocusStack.pop();
try {
- focusOwner.mFocusDispatcher.dispatchAudioFocusChange(
- AudioManager.AUDIOFOCUS_LOSS, focusOwner.mClientId);
+ exFocusOwner.mFocusDispatcher.dispatchAudioFocusChange(
+ AudioManager.AUDIOFOCUS_LOSS, exFocusOwner.mClientId);
} catch (RemoteException e) {
Log.e(TAG, "Failure to signal loss of audio focus due to "+ e);
e.printStackTrace();
}
- focusOwner.unlinkToDeath();
+ exFocusOwner.unlinkToDeath();
// clear RCD
synchronized(mRCStack) {
clearRemoteControlDisplay_syncAfRcs();
@@ -288,9 +293,11 @@
// notify the top of the stack it gained focus
if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
if (canReassignAudioFocus()) {
+ final FocusStackEntry newFocusOwner = mFocusStack.peek();
try {
- mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
+ newFocusOwner.mFocusDispatcher.dispatchAudioFocusChange(
AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
+ newFocusOwner.mFocusLossReceived = AUDIOFOCUS_NONE;
} catch (RemoteException e) {
Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
e.printStackTrace();
@@ -304,22 +311,53 @@
public IAudioFocusDispatcher mFocusDispatcher = null;
public IBinder mSourceRef = null;
public String mClientId;
- public int mFocusChangeType;
+ /** the audio focus gain request that caused the addition of this entry in the stack */
+ public int mFocusGainRequest;
+ public int mFocusLossReceived;
public AudioFocusDeathHandler mHandler;
public String mPackageName;
public int mCallingUid;
- public FocusStackEntry() {
+ private static String focusChangeToString(int focus) {
+ switch(focus) {
+ case AudioManager.AUDIOFOCUS_GAIN:
+ return "GAIN";
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
+ return "GAIN_TRANSIENT";
+ case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
+ return "GAIN_TRANSIENT_MAY_DUCK";
+ case AudioManager.AUDIOFOCUS_LOSS:
+ return "LOSS";
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ return "LOSS_TRANSIENT";
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ return "LOSS_TRANSIENT_CAN_DUCK";
+ default:
+ return "[invalid focus change" + focus + "]";
+ }
}
- public FocusStackEntry(int streamType, int duration,
+ String focusGainToString() {
+ return focusChangeToString(mFocusGainRequest);
+ }
+
+ String focusLossToString() {
+ if (mFocusLossReceived == 0) {
+ return "none";
+ } else {
+ return focusChangeToString(mFocusLossReceived);
+ }
+ }
+
+ FocusStackEntry(int streamType, int focusRequest,
IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
String pn, int uid) {
mStreamType = streamType;
mFocusDispatcher = afl;
mSourceRef = source;
mClientId = id;
- mFocusChangeType = duration;
+ mFocusGainRequest = focusRequest;
+ mFocusLossReceived = AUDIOFOCUS_NONE;
mHandler = hdlr;
mPackageName = pn;
mCallingUid = uid;
@@ -358,7 +396,8 @@
pw.println(" source:" + fse.mSourceRef
+ " -- pack: " + fse.mPackageName
+ " -- client: " + fse.mClientId
- + " -- duration: " + fse.mFocusChangeType
+ + " -- gain: " + fse.focusGainToString()
+ + " -- loss: " + fse.focusLossToString()
+ " -- uid: " + fse.mCallingUid
+ " -- stream: " + fse.mStreamType);
}
@@ -513,7 +552,7 @@
if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
// if focus is already owned by this client and the reason for acquiring the focus
// hasn't changed, don't do anything
- if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
+ if (mFocusStack.peek().mFocusGainRequest == focusChangeHint) {
// unlink death handler so it can be gc'ed.
// linkToDeath() creates a JNI global reference preventing collection.
cb.unlinkToDeath(afdh, 0);
@@ -527,12 +566,14 @@
// notify current top of stack it is losing focus
if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
+ final FocusStackEntry exFocusOwner = mFocusStack.peek();
try {
- mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
+ exFocusOwner.mFocusDispatcher.dispatchAudioFocusChange(
-1 * focusChangeHint, // loss and gain codes are inverse of each other
mFocusStack.peek().mClientId);
+ exFocusOwner.mFocusLossReceived = -1 * focusChangeHint;
} catch (RemoteException e) {
- Log.e(TAG, " Failure to signal loss of focus due to "+ e);
+ Log.e(TAG, " Failure to signal loss of focus: ", e);
e.printStackTrace();
}
}
@@ -1557,7 +1598,7 @@
for (int index = mFocusStack.size()-1; index >= 0; index--) {
FocusStackEntry fse = mFocusStack.elementAt(index);
if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
- || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
+ || (fse.mFocusGainRequest == AudioManager.AUDIOFOCUS_GAIN)) {
af = fse;
break;
}
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index d876bd2..c1c965a 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -300,7 +300,7 @@
ALOG_ASSERT(size != NULL, "size is NULL!!!");
ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
- ALOGV("%s: buffer: 0x%p", __FUNCTION__, buffer);
+ ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
uint32_t dataSize, ySize, cSize, cStride;
uint8_t *cb, *cr;
@@ -633,7 +633,7 @@
}
status_t res = consumer->lockNextBuffer(buffer);
if (res != NO_ERROR) {
- ALOGE("%s Fail to lockNextBuffer with error: 0x%x ", __FUNCTION__, res);
+ ALOGE("%s Fail to lockNextBuffer with error: %d ", __FUNCTION__, res);
return false;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
index 2ebe11a..1be2a62 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
@@ -19,6 +19,7 @@
protected static final int USE_CALLING_UID = -1;
protected static final int BAD_VALUE = -22;
+ protected static final int INVALID_OPERATION = -38;
protected static final int ALREADY_EXISTS = -17;
public static final int NO_ERROR = 0;
private final Context mContext;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 5e4fabd..a9a0757 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -307,4 +307,49 @@
assertNotNull(info.get(CameraPropertiesKeys.Scaler.AVAILABLE_FORMATS));
}
+ @SmallTest
+ public void testWaitUntilIdle() throws Exception {
+ CameraMetadata metadata = new CameraMetadata();
+ assertTrue(metadata.isEmpty());
+
+ CaptureRequest request = new CaptureRequest();
+ assertTrue(request.isEmpty());
+
+ // Create default request from template.
+ int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
+ assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ assertFalse(metadata.isEmpty());
+
+ request.swap(metadata);
+ assertFalse(request.isEmpty());
+ assertTrue(metadata.isEmpty());
+
+ SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
+ surfaceTexture.setDefaultBufferSize(640, 480);
+ Surface surface = new Surface(surfaceTexture);
+
+ // Create stream first. Pre-requisite to submitting a request using that
+ // stream.
+
+ int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, /* ignored */30,
+ surface);
+ assertEquals(0, streamId);
+
+ request.addTarget(surface);
+
+ int requestIdStreaming = mCameraUser.submitRequest(request, /* streaming */true);
+ assertTrue("Request IDs should be non-negative", requestIdStreaming >= 0);
+
+ // Test Bad case first: waitUntilIdle when there is active repeating request
+ status = mCameraUser.waitUntilIdle();
+ assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
+ CameraBinderTestUtils.INVALID_OPERATION, status);
+
+ // Test good case, waitUntilIdle when there is no active repeating request
+ status = mCameraUser.cancelRequest(requestIdStreaming);
+ assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ status = mCameraUser.waitUntilIdle();
+ assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+ }
+
}
diff --git a/packages/Keyguard/res/values-hdpi/dimens.xml b/packages/Keyguard/res/values-sw320dp/dimens.xml
similarity index 100%
rename from packages/Keyguard/res/values-hdpi/dimens.xml
rename to packages/Keyguard/res/values-sw320dp/dimens.xml
diff --git a/packages/Keyguard/res/values-sw360dp/dimens.xml b/packages/Keyguard/res/values-sw360dp/dimens.xml
new file mode 100644
index 0000000..41d6ac0
--- /dev/null
+++ b/packages/Keyguard/res/values-sw360dp/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+
+ <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+ <dimen name="keyguard_security_height">400dp</dimen>
+
+</resources>
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index 4a5c0d5..a56af08 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.accounts.Account;
import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentService;
@@ -26,6 +27,7 @@
import android.content.PeriodicSync;
import android.content.SyncAdapterType;
import android.content.SyncInfo;
+import android.content.SyncRequest;
import android.content.SyncStatusInfo;
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
@@ -39,6 +41,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -312,6 +315,7 @@
}
}
+ @Override
public void requestSync(Account account, String authority, Bundle extras) {
ContentResolver.validateSyncExtrasBundle(extras);
int userId = UserHandle.getCallingUserId();
@@ -323,7 +327,8 @@
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.scheduleSync(account, userId, uId, authority, extras, 0 /* no delay */,
+ syncManager.scheduleSync(account, userId, uId, authority, extras,
+ 0 /* no delay */, 0 /* no delay */,
false /* onlyThoseWithUnkownSyncableState */);
}
} finally {
@@ -332,11 +337,83 @@
}
/**
+ * Request a sync with a generic {@link android.content.SyncRequest} object. This will be
+ * either:
+ * periodic OR one-off sync.
+ * and
+ * anonymous OR provider sync.
+ * Depending on the request, we enqueue to suit in the SyncManager.
+ * @param request
+ */
+ @Override
+ public void sync(SyncRequest request) {
+ Bundle extras = request.getBundle();
+ ContentResolver.validateSyncExtrasBundle(extras);
+
+ long flextime = request.getSyncFlexTime();
+ long runAtTime = request.getSyncRunTime();
+ int userId = UserHandle.getCallingUserId();
+ int uId = Binder.getCallingUid();
+
+ // This makes it so that future permission checks will be in the context of this
+ // process rather than the caller's process. We will restore this before returning.
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ if (request.hasAuthority()) {
+ // Sync Adapter registered with the system - old API.
+ final Account account = request.getProviderInfo().first;
+ final String provider = request.getProviderInfo().second;
+ if (request.isPeriodic()) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ if (runAtTime < 60) {
+ Slog.w(TAG, "Requested poll frequency of " + runAtTime
+ + " seconds being rounded up to 60 seconds.");
+ runAtTime = 60;
+ }
+ PeriodicSync syncToAdd =
+ new PeriodicSync(account, provider, extras, runAtTime, flextime);
+ getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
+ } else {
+ long beforeRuntimeMillis = (flextime) * 1000;
+ long runtimeMillis = runAtTime * 1000;
+ syncManager.scheduleSync(
+ account, userId, uId, provider, extras,
+ beforeRuntimeMillis, runtimeMillis,
+ false /* onlyThoseWithUnknownSyncableState */);
+ }
+ } else {
+ // Anonymous sync - new API.
+ final ComponentName syncService = request.getService();
+ if (request.isPeriodic()) {
+ throw new RuntimeException("Periodic anonymous syncs not implemented yet.");
+ } else {
+ long beforeRuntimeMillis = (flextime) * 1000;
+ long runtimeMillis = runAtTime * 1000;
+ syncManager.scheduleSync(
+ syncService, userId, uId, extras,
+ beforeRuntimeMillis,
+ runtimeMillis,
+ false /* onlyThoseWithUnknownSyncableState */); // Empty function.
+ throw new RuntimeException("One-off anonymous syncs not implemented yet.");
+ }
+ }
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ /**
* Clear all scheduled sync operations that match the uri and cancel the active sync
* if they match the authority and account, if they are present.
* @param account filter the pending and active syncs to cancel using this account
* @param authority filter the pending and active syncs to cancel using this authority
*/
+ @Override
public void cancelSync(Account account, String authority) {
int userId = UserHandle.getCallingUserId();
@@ -358,6 +435,7 @@
* Get information about the SyncAdapters that are known to the system.
* @return an array of SyncAdapters that have registered with the system
*/
+ @Override
public SyncAdapterType[] getSyncAdapterTypes() {
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
@@ -371,6 +449,7 @@
}
}
+ @Override
public boolean getSyncAutomatically(Account account, String providerName) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
@@ -389,6 +468,7 @@
return false;
}
+ @Override
public void setSyncAutomatically(Account account, String providerName, boolean sync) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
@@ -406,6 +486,10 @@
}
}
+ /**
+ * Old API. Schedule periodic sync with default flex time.
+ */
+ @Override
public void addPeriodicSync(Account account, String authority, Bundle extras,
long pollFrequency) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
@@ -420,13 +504,18 @@
long identityToken = clearCallingIdentity();
try {
- getSyncManager().getSyncStorageEngine().addPeriodicSync(
- account, userId, authority, extras, pollFrequency);
+ // Add default flex time to this sync.
+ PeriodicSync syncToAdd =
+ new PeriodicSync(account, authority, extras,
+ pollFrequency,
+ SyncStorageEngine.calculateDefaultFlexTime(pollFrequency));
+ getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
} finally {
restoreCallingIdentity(identityToken);
}
}
+ @Override
public void removePeriodicSync(Account account, String authority, Bundle extras) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
@@ -434,13 +523,23 @@
long identityToken = clearCallingIdentity();
try {
- getSyncManager().getSyncStorageEngine().removePeriodicSync(account, userId, authority,
- extras);
+ PeriodicSync syncToRemove = new PeriodicSync(account, authority, extras,
+ 0 /* Not read for removal */, 0 /* Not read for removal */);
+ getSyncManager().getSyncStorageEngine().removePeriodicSync(syncToRemove, userId);
} finally {
restoreCallingIdentity(identityToken);
}
}
+ /**
+ * TODO: Implement.
+ * @param request Sync to remove.
+ */
+ public void removeSync(SyncRequest request) {
+
+ }
+
+ @Override
public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
@@ -473,6 +572,7 @@
return -1;
}
+ @Override
public void setIsSyncable(Account account, String providerName, int syncable) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
@@ -490,6 +590,7 @@
}
}
+ @Override
public boolean getMasterSyncAutomatically() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
@@ -507,6 +608,7 @@
return false;
}
+ @Override
public void setMasterSyncAutomatically(boolean flag) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index 2da95c3..ee5b890 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -34,6 +34,7 @@
import android.content.ISyncStatusObserver;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.PeriodicSync;
import android.content.ServiceConnection;
import android.content.SyncActivityTooManyDeletes;
import android.content.SyncAdapterType;
@@ -83,6 +84,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -190,6 +192,7 @@
private BroadcastReceiver mStorageIntentReceiver =
new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
@@ -210,36 +213,39 @@
};
private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
mSyncHandler.onBootCompleted();
}
};
private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
if (getConnectivityManager().getBackgroundDataSetting()) {
scheduleSync(null /* account */, UserHandle.USER_ALL,
SyncOperation.REASON_BACKGROUND_DATA_SETTINGS_CHANGED,
null /* authority */,
- new Bundle(), 0 /* delay */,
+ new Bundle(), 0 /* delay */, 0 /* delay */,
false /* onlyThoseWithUnknownSyncableState */);
}
}
};
private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
updateRunningAccounts();
// Kick off sync for everyone, since this was a radical account change
scheduleSync(null, UserHandle.USER_ALL, SyncOperation.REASON_ACCOUNTS_UPDATED, null,
- null, 0 /* no delay */, false);
+ null, 0 /* no delay */, 0/* no delay */, false);
}
};
private final PowerManager mPowerManager;
- // Use this as a random offset to seed all periodic syncs
+ // Use this as a random offset to seed all periodic syncs.
private int mSyncRandomOffsetMillis;
private final UserManager mUserManager;
@@ -296,6 +302,7 @@
private BroadcastReceiver mConnectivityIntentReceiver =
new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
final boolean wasConnected = mDataConnectionIsConnected;
@@ -321,6 +328,7 @@
private BroadcastReceiver mShutdownIntentReceiver =
new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "Writing sync state before shutdown...");
getSyncStorageEngine().writeAllState();
@@ -371,9 +379,13 @@
SyncStorageEngine.init(context);
mSyncStorageEngine = SyncStorageEngine.getSingleton();
mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
+ @Override
public void onSyncRequest(Account account, int userId, int reason, String authority,
Bundle extras) {
- scheduleSync(account, userId, reason, authority, extras, 0, false);
+ scheduleSync(account, userId, reason, authority, extras,
+ 0 /* no delay */,
+ 0 /* no delay */,
+ false);
}
});
@@ -388,7 +400,7 @@
if (!removed) {
scheduleSync(null, UserHandle.USER_ALL,
SyncOperation.REASON_SERVICE_CHANGED,
- type.authority, null, 0 /* no delay */,
+ type.authority, null, 0 /* no delay */, 0 /* no delay */,
false /* onlyThoseWithUnkownSyncableState */);
}
}
@@ -453,6 +465,7 @@
mSyncStorageEngine.addStatusChangeListener(
ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() {
+ @Override
public void onStatusChanged(int which) {
// force the sync loop to run if the settings change
sendCheckAlarmsMessage();
@@ -526,58 +539,35 @@
}
/**
- * Initiate a sync. This can start a sync for all providers
- * (pass null to url, set onlyTicklable to false), only those
- * providers that are marked as ticklable (pass null to url,
- * set onlyTicklable to true), or a specific provider (set url
- * to the content url of the provider).
- *
- * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is
- * true then initiate a sync that just checks for local changes to send
- * to the server, otherwise initiate a sync that first gets any
- * changes from the server before sending local changes back to
- * the server.
- *
- * <p>If a specific provider is being synced (the url is non-null)
- * then the extras can contain SyncAdapter-specific information
- * to control what gets synced (e.g. which specific feed to sync).
- *
- * <p>You'll start getting callbacks after this.
- *
- * @param requestedAccount the account to sync, may be null to signify all accounts
+ * Initiate a sync using the new anonymous service API.
+ * TODO: Implement.
+ * @param cname SyncService component bound to in order to perform the sync.
* @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
* then all users' accounts are considered.
- * @param reason for sync request. If this is a positive integer, it is the Linux uid
- * assigned to the process that requested the sync. If it's negative, the sync was requested by
- * the SyncManager itself and could be one of the following:
- * {@link SyncOperation#REASON_BACKGROUND_DATA_SETTINGS_CHANGED}
- * {@link SyncOperation#REASON_ACCOUNTS_UPDATED}
- * {@link SyncOperation#REASON_SERVICE_CHANGED}
- * {@link SyncOperation#REASON_PERIODIC}
- * {@link SyncOperation#REASON_IS_SYNCABLE}
- * {@link SyncOperation#REASON_SYNC_AUTO}
- * {@link SyncOperation#REASON_MASTER_SYNC_AUTO}
- * {@link SyncOperation#REASON_USER_START}
- * @param requestedAuthority the authority to sync, may be null to indicate all authorities
+ * @param uid Linux uid of the application that is performing the sync.
* @param extras a Map of SyncAdapter-specific information to control
- * syncs of a specific provider. Can be null. Is ignored
- * if the url is null.
- * @param delay how many milliseconds in the future to wait before performing this
- * @param onlyThoseWithUnkownSyncableState
+ * syncs of a specific provider. Can be null.
+ * @param beforeRunTimeMillis
+ * @param runtimeMillis
*/
- public void scheduleSync(Account requestedAccount, int userId, int reason,
- String requestedAuthority, Bundle extras, long delay,
- boolean onlyThoseWithUnkownSyncableState) {
+ public void scheduleSync(ComponentName cname, int userId, int uid, Bundle extras,
+ long beforeRunTimeMillis, long runtimeMillis,
+ boolean onlyThoseWithUnknownSyncableState) {
+/**
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
final boolean backgroundDataUsageAllowed = !mBootCompleted ||
getConnectivityManager().getBackgroundDataSetting();
- if (extras == null) extras = new Bundle();
-
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ if (isLoggable) {
+ Log.e(TAG, requestedAccount + " " + extras.toString() + " " + requestedAuthority);
+ }
Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
if (expedited) {
- delay = -1; // this means schedule at the front of the queue
+ runtimeMillis = -1; // this means schedule at the front of the queue
}
AccountAndUser[] accounts;
@@ -682,11 +672,13 @@
account.userId, authority);
final long backoffTime = backoff != null ? backoff.first : 0;
if (isSyncable < 0) {
+ // Initialisation sync.
Bundle newExtras = new Bundle();
newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
if (isLoggable) {
- Log.v(TAG, "scheduleSync:"
- + " delay " + delay
+ Log.v(TAG, "schedule initialisation Sync:"
+ + ", delay until " + delayUntil
+ + ", run by " + 0
+ ", source " + source
+ ", account " + account
+ ", authority " + authority
@@ -694,13 +686,15 @@
}
scheduleSyncOperation(
new SyncOperation(account.account, account.userId, reason, source,
- authority, newExtras, 0, backoffTime, delayUntil,
- allowParallelSyncs));
+ authority, newExtras, 0 /* immediate , 0 /* No flex time,
+ backoffTime, delayUntil, allowParallelSyncs));
}
if (!onlyThoseWithUnkownSyncableState) {
if (isLoggable) {
Log.v(TAG, "scheduleSync:"
- + " delay " + delay
+ + " delay until " + delayUntil
+ + " run by " + runtimeMillis
+ + " flex " + beforeRuntimeMillis
+ ", source " + source
+ ", account " + account
+ ", authority " + authority
@@ -708,17 +702,223 @@
}
scheduleSyncOperation(
new SyncOperation(account.account, account.userId, reason, source,
- authority, extras, delay, backoffTime, delayUntil,
- allowParallelSyncs));
+ authority, extras, runtimeMillis, beforeRuntimeMillis,
+ backoffTime, delayUntil, allowParallelSyncs));
+ }
+ }
+ }*/
+ }
+
+ /**
+ * Initiate a sync. This can start a sync for all providers
+ * (pass null to url, set onlyTicklable to false), only those
+ * providers that are marked as ticklable (pass null to url,
+ * set onlyTicklable to true), or a specific provider (set url
+ * to the content url of the provider).
+ *
+ * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is
+ * true then initiate a sync that just checks for local changes to send
+ * to the server, otherwise initiate a sync that first gets any
+ * changes from the server before sending local changes back to
+ * the server.
+ *
+ * <p>If a specific provider is being synced (the url is non-null)
+ * then the extras can contain SyncAdapter-specific information
+ * to control what gets synced (e.g. which specific feed to sync).
+ *
+ * <p>You'll start getting callbacks after this.
+ *
+ * @param requestedAccount the account to sync, may be null to signify all accounts
+ * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
+ * then all users' accounts are considered.
+ * @param reason for sync request. If this is a positive integer, it is the Linux uid
+ * assigned to the process that requested the sync. If it's negative, the sync was requested by
+ * the SyncManager itself and could be one of the following:
+ * {@link SyncOperation#REASON_BACKGROUND_DATA_SETTINGS_CHANGED}
+ * {@link SyncOperation#REASON_ACCOUNTS_UPDATED}
+ * {@link SyncOperation#REASON_SERVICE_CHANGED}
+ * {@link SyncOperation#REASON_PERIODIC}
+ * {@link SyncOperation#REASON_IS_SYNCABLE}
+ * {@link SyncOperation#REASON_SYNC_AUTO}
+ * {@link SyncOperation#REASON_MASTER_SYNC_AUTO}
+ * {@link SyncOperation#REASON_USER_START}
+ * @param requestedAuthority the authority to sync, may be null to indicate all authorities
+ * @param extras a Map of SyncAdapter-specific information to control
+ * syncs of a specific provider. Can be null. Is ignored
+ * if the url is null.
+ * @param beforeRuntimeMillis milliseconds before runtimeMillis that this sync can run.
+ * @param runtimeMillis maximum milliseconds in the future to wait before performing sync.
+ * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
+ */
+ public void scheduleSync(Account requestedAccount, int userId, int reason,
+ String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
+ long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
+ boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+
+ final boolean backgroundDataUsageAllowed = !mBootCompleted ||
+ getConnectivityManager().getBackgroundDataSetting();
+
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ if (isLoggable) {
+ Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "
+ + requestedAuthority);
+ }
+ Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
+ if (expedited) {
+ runtimeMillis = -1; // this means schedule at the front of the queue
+ }
+
+ AccountAndUser[] accounts;
+ if (requestedAccount != null && userId != UserHandle.USER_ALL) {
+ accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
+ } else {
+ // if the accounts aren't configured yet then we can't support an account-less
+ // sync request
+ accounts = mRunningAccounts;
+ if (accounts.length == 0) {
+ if (isLoggable) {
+ Log.v(TAG, "scheduleSync: no accounts configured, dropping");
+ }
+ return;
+ }
+ }
+
+ final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
+ final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
+ if (manualSync) {
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+ }
+ final boolean ignoreSettings =
+ extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
+
+ int source;
+ if (uploadOnly) {
+ source = SyncStorageEngine.SOURCE_LOCAL;
+ } else if (manualSync) {
+ source = SyncStorageEngine.SOURCE_USER;
+ } else if (requestedAuthority == null) {
+ source = SyncStorageEngine.SOURCE_POLL;
+ } else {
+ // this isn't strictly server, since arbitrary callers can (and do) request
+ // a non-forced two-way sync on a specific url
+ source = SyncStorageEngine.SOURCE_SERVER;
+ }
+
+ for (AccountAndUser account : accounts) {
+ // Compile a list of authorities that have sync adapters.
+ // For each authority sync each account that matches a sync adapter.
+ final HashSet<String> syncableAuthorities = new HashSet<String>();
+ for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
+ mSyncAdapters.getAllServices(account.userId)) {
+ syncableAuthorities.add(syncAdapter.type.authority);
+ }
+
+ // if the url was specified then replace the list of authorities
+ // with just this authority or clear it if this authority isn't
+ // syncable
+ if (requestedAuthority != null) {
+ final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
+ syncableAuthorities.clear();
+ if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
+ }
+
+ for (String authority : syncableAuthorities) {
+ int isSyncable = getIsSyncable(account.account, account.userId,
+ authority);
+ if (isSyncable == 0) {
+ continue;
+ }
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(authority, account.account.type), account.userId);
+ if (syncAdapterInfo == null) {
+ continue;
+ }
+ final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
+ final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
+ if (isSyncable < 0 && isAlwaysSyncable) {
+ mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1);
+ isSyncable = 1;
+ }
+ if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
+ continue;
+ }
+ if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
+ continue;
+ }
+
+ // always allow if the isSyncable state is unknown
+ boolean syncAllowed =
+ (isSyncable < 0)
+ || ignoreSettings
+ || (backgroundDataUsageAllowed
+ && mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
+ && mSyncStorageEngine.getSyncAutomatically(account.account,
+ account.userId, authority));
+ if (!syncAllowed) {
+ if (isLoggable) {
+ Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
+ + " is not allowed, dropping request");
+ }
+ continue;
+ }
+
+ Pair<Long, Long> backoff = mSyncStorageEngine
+ .getBackoff(account.account, account.userId, authority);
+ long delayUntil = mSyncStorageEngine.getDelayUntilTime(account.account,
+ account.userId, authority);
+ final long backoffTime = backoff != null ? backoff.first : 0;
+ if (isSyncable < 0) {
+ // Initialisation sync.
+ Bundle newExtras = new Bundle();
+ newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+ if (isLoggable) {
+ Log.v(TAG, "schedule initialisation Sync:"
+ + ", delay until " + delayUntil
+ + ", run by " + 0
+ + ", source " + source
+ + ", account " + account
+ + ", authority " + authority
+ + ", extras " + newExtras);
+ }
+ scheduleSyncOperation(
+ new SyncOperation(account.account, account.userId, reason, source,
+ authority, newExtras, 0 /* immediate */, 0 /* No flex time*/,
+ backoffTime, delayUntil, allowParallelSyncs));
+ }
+ if (!onlyThoseWithUnkownSyncableState) {
+ if (isLoggable) {
+ Log.v(TAG, "scheduleSync:"
+ + " delay until " + delayUntil
+ + " run by " + runtimeMillis
+ + " flex " + beforeRuntimeMillis
+ + ", source " + source
+ + ", account " + account
+ + ", authority " + authority
+ + ", extras " + extras);
+ }
+ scheduleSyncOperation(
+ new SyncOperation(account.account, account.userId, reason, source,
+ authority, extras, runtimeMillis, beforeRuntimeMillis,
+ backoffTime, delayUntil, allowParallelSyncs));
}
}
}
}
+ /**
+ * Schedule sync based on local changes to a provider. Occurs within interval
+ * [LOCAL_SYNC_DELAY, 2*LOCAL_SYNC_DELAY].
+ */
public void scheduleLocalSync(Account account, int userId, int reason, String authority) {
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
- scheduleSync(account, userId, reason, authority, extras, LOCAL_SYNC_DELAY,
+ scheduleSync(account, userId, reason, authority, extras,
+ LOCAL_SYNC_DELAY /* earliest run time */,
+ 2 * LOCAL_SYNC_DELAY /* latest sync time. */,
false /* onlyThoseWithUnkownSyncableState */);
}
@@ -775,6 +975,7 @@
}
class SyncAlarmIntentReceiver extends BroadcastReceiver {
+ @Override
public void onReceive(Context context, Intent intent) {
mHandleAlarmWakeLock.acquire();
sendSyncAlarmMessage();
@@ -943,11 +1144,13 @@
Log.d(TAG, "retrying sync operation that failed because there was already a "
+ "sync in progress: " + operation);
}
- scheduleSyncOperation(new SyncOperation(operation.account, operation.userId,
+ scheduleSyncOperation(
+ new SyncOperation(
+ operation.account, operation.userId,
operation.reason,
operation.syncSource,
operation.authority, operation.extras,
- DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000,
+ DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000, operation.flexTime,
operation.backoff, operation.delayUntil, operation.allowParallelSyncs));
} else if (syncResult.hasSoftError()) {
if (isLoggable) {
@@ -977,7 +1180,8 @@
final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
for (Account account : accounts) {
scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
- 0 /* no delay */, true /* onlyThoseWithUnknownSyncableState */);
+ 0 /* no delay */, 0 /* No flex */,
+ true /* onlyThoseWithUnknownSyncableState */);
}
sendCheckAlarmsMessage();
@@ -1204,7 +1408,10 @@
synchronized (mSyncQueue) {
sb.setLength(0);
mSyncQueue.dump(sb);
+ // Dump Pending Operations.
+ getSyncStorageEngine().dumpPendingOperations(sb);
}
+
pw.println();
pw.print(sb.toString());
@@ -1271,12 +1478,15 @@
for (int i = 0; i < settings.periodicSyncs.size(); i++) {
- final Pair<Bundle, Long> pair = settings.periodicSyncs.get(i);
- final String period = String.valueOf(pair.second);
- final String extras = pair.first.size() > 0 ? " " + pair.first.toString() : "";
- final String next = formatTime(status.getPeriodicSyncTime(i)
- + pair.second * 1000);
- table.set(row + i * 2, 12, period + extras);
+ final PeriodicSync sync = settings.periodicSyncs.get(i);
+ final String period =
+ String.format("[p:%d s, f: %d s]", sync.period, sync.flexTime);
+ final String extras =
+ sync.extras.size() > 0 ?
+ sync.extras.toString() : "Bundle[]";
+ final String next = "Next sync: " + formatTime(status.getPeriodicSyncTime(i)
+ + sync.period * 1000);
+ table.set(row + i * 2, 12, period + " " + extras);
table.set(row + i * 2 + 1, 12, next);
}
@@ -1810,6 +2020,7 @@
super(looper);
}
+ @Override
public void handleMessage(Message msg) {
long earliestFuturePollTime = Long.MAX_VALUE;
long nextPendingSyncTime = Long.MAX_VALUE;
@@ -1827,7 +2038,7 @@
earliestFuturePollTime = scheduleReadyPeriodicSyncs();
switch (msg.what) {
case SyncHandler.MESSAGE_CANCEL: {
- Pair<Account, String> payload = (Pair<Account, String>)msg.obj;
+ Pair<Account, String> payload = (Pair<Account, String>) msg.obj;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CANCEL: "
+ payload.first + ", " + payload.second);
@@ -1934,6 +2145,10 @@
* in milliseconds since boot
*/
private long scheduleReadyPeriodicSyncs() {
+ final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ if (isLoggable) {
+ Log.v(TAG, "scheduleReadyPeriodicSyncs");
+ }
final boolean backgroundDataUsageAllowed =
getConnectivityManager().getBackgroundDataSetting();
long earliestFuturePollTime = Long.MAX_VALUE;
@@ -1973,37 +2188,59 @@
}
for (int i = 0, N = authorityInfo.periodicSyncs.size(); i < N; i++) {
- final Bundle extras = authorityInfo.periodicSyncs.get(i).first;
- final Long periodInMillis = authorityInfo.periodicSyncs.get(i).second * 1000;
- // Skip if the period is invalid
+ final PeriodicSync sync = authorityInfo.periodicSyncs.get(i);
+ final Bundle extras = sync.extras;
+ final Long periodInMillis = sync.period * 1000;
+ final Long flexInMillis = sync.flexTime * 1000;
+ // Skip if the period is invalid.
if (periodInMillis <= 0) {
continue;
}
- // find when this periodic sync was last scheduled to run
+ // Find when this periodic sync was last scheduled to run.
final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i);
-
+ final long shiftedLastPollTimeAbsolute =
+ (0 < lastPollTimeAbsolute - mSyncRandomOffsetMillis) ?
+ (lastPollTimeAbsolute - mSyncRandomOffsetMillis) : 0;
long remainingMillis
- = periodInMillis - (shiftedNowAbsolute % periodInMillis);
-
+ = periodInMillis - (shiftedNowAbsolute % periodInMillis);
+ long timeSinceLastRunMillis
+ = (nowAbsolute - lastPollTimeAbsolute);
+ // Schedule this periodic sync to run early if it's close enough to its next
+ // runtime, and far enough from its last run time.
+ // If we are early, there will still be time remaining in this period.
+ boolean runEarly = remainingMillis <= flexInMillis
+ && timeSinceLastRunMillis > periodInMillis - flexInMillis;
+ if (isLoggable) {
+ Log.v(TAG, "sync: " + i + " for " + authorityInfo.authority + "."
+ + " period: " + (periodInMillis)
+ + " flex: " + (flexInMillis)
+ + " remaining: " + (remainingMillis)
+ + " time_since_last: " + timeSinceLastRunMillis
+ + " last poll absol: " + lastPollTimeAbsolute
+ + " last poll shifed: " + shiftedLastPollTimeAbsolute
+ + " shifted now: " + shiftedNowAbsolute
+ + " run_early: " + runEarly);
+ }
/*
* Sync scheduling strategy: Set the next periodic sync
* based on a random offset (in seconds). Also sync right
* now if any of the following cases hold and mark it as
* having been scheduled
- * Case 1: This sync is ready to run
- * now.
+ * Case 1: This sync is ready to run now.
* Case 2: If the lastPollTimeAbsolute is in the
* future, sync now and reinitialize. This can happen for
* example if the user changed the time, synced and changed
* back.
* Case 3: If we failed to sync at the last scheduled
- * time
+ * time.
+ * Case 4: This sync is close enough to the time that we can schedule it.
*/
- if (remainingMillis == periodInMillis // Case 1
+ if (runEarly // Case 4
+ || remainingMillis == periodInMillis // Case 1
|| lastPollTimeAbsolute > nowAbsolute // Case 2
- || (nowAbsolute - lastPollTimeAbsolute
- >= periodInMillis)) { // Case 3
+ || timeSinceLastRunMillis >= periodInMillis) { // Case 3
// Sync now
+
final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
authorityInfo.account, authorityInfo.userId,
authorityInfo.authority);
@@ -2015,24 +2252,29 @@
if (syncAdapterInfo == null) {
continue;
}
+ mSyncStorageEngine.setPeriodicSyncTime(authorityInfo.ident,
+ authorityInfo.periodicSyncs.get(i), nowAbsolute);
scheduleSyncOperation(
new SyncOperation(authorityInfo.account, authorityInfo.userId,
SyncOperation.REASON_PERIODIC,
SyncStorageEngine.SOURCE_PERIODIC,
- authorityInfo.authority, extras, 0 /* delay */,
+ authorityInfo.authority, extras,
+ 0 /* runtime */, 0 /* flex */,
backoff != null ? backoff.first : 0,
mSyncStorageEngine.getDelayUntilTime(
authorityInfo.account, authorityInfo.userId,
authorityInfo.authority),
syncAdapterInfo.type.allowParallelSyncs()));
- mSyncStorageEngine.setPeriodicSyncTime(authorityInfo.ident,
- authorityInfo.periodicSyncs.get(i), nowAbsolute);
+
}
- // Compute when this periodic sync should next run
- final long nextPollTimeAbsolute = nowAbsolute + remainingMillis;
-
- // remember this time if it is earlier than
- // earliestFuturePollTime
+ // Compute when this periodic sync should next run.
+ long nextPollTimeAbsolute;
+ if (runEarly) {
+ // Add the time remaining so we don't get out of phase.
+ nextPollTimeAbsolute = nowAbsolute + periodInMillis + remainingMillis;
+ } else {
+ nextPollTimeAbsolute = nowAbsolute + remainingMillis;
+ }
if (nextPollTimeAbsolute < earliestFuturePollTime) {
earliestFuturePollTime = nextPollTimeAbsolute;
}
@@ -2044,10 +2286,9 @@
}
// convert absolute time to elapsed time
- return SystemClock.elapsedRealtime()
- + ((earliestFuturePollTime < nowAbsolute)
- ? 0
- : (earliestFuturePollTime - nowAbsolute));
+ return SystemClock.elapsedRealtime() +
+ ((earliestFuturePollTime < nowAbsolute) ?
+ 0 : (earliestFuturePollTime - nowAbsolute));
}
private long maybeStartNextSyncLocked() {
@@ -2097,8 +2338,8 @@
Log.v(TAG, "build the operation array, syncQueue size is "
+ mSyncQueue.getOperations().size());
}
- final Iterator<SyncOperation> operationIterator = mSyncQueue.getOperations()
- .iterator();
+ final Iterator<SyncOperation> operationIterator =
+ mSyncQueue.getOperations().iterator();
final ActivityManager activityManager
= (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -2106,40 +2347,52 @@
while (operationIterator.hasNext()) {
final SyncOperation op = operationIterator.next();
- // drop the sync if the account of this operation no longer exists
+ // Drop the sync if the account of this operation no longer exists.
if (!containsAccountAndUser(accounts, op.account, op.userId)) {
operationIterator.remove();
mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: account doesn't exist.");
+ }
continue;
}
- // drop this sync request if it isn't syncable
+ // Drop this sync request if it isn't syncable.
int syncableState = getIsSyncable(
op.account, op.userId, op.authority);
if (syncableState == 0) {
operationIterator.remove();
mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: isSyncable == 0.");
+ }
continue;
}
- // if the user in not running, drop the request
+ // If the user is not running, drop the request.
if (!activityManager.isUserRunning(op.userId)) {
final UserInfo userInfo = mUserManager.getUserInfo(op.userId);
if (userInfo == null) {
removedUsers.add(op.userId);
}
- continue;
- }
-
- // if the next run time is in the future, meaning there are no syncs ready
- // to run, return the time
- if (op.effectiveRunTime > now) {
- if (nextReadyToRunTime > op.effectiveRunTime) {
- nextReadyToRunTime = op.effectiveRunTime;
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: user not running.");
}
continue;
}
+ // If the next run time is in the future, even given the flexible scheduling,
+ // return the time.
+ if (op.effectiveRunTime - op.flexTime > now) {
+ if (nextReadyToRunTime > op.effectiveRunTime) {
+ nextReadyToRunTime = op.effectiveRunTime;
+ }
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: Sync too far in future.");
+ }
+ continue;
+ }
+ // TODO: change this behaviour for non-registered syncs.
final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
syncAdapterInfo = mSyncAdapters.getServiceInfo(
SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
@@ -2180,7 +2433,7 @@
}
// find the next operation to dispatch, if one is ready
- // iterate from the top, keep issuing (while potentially cancelling existing syncs)
+ // iterate from the top, keep issuing (while potentially canceling existing syncs)
// until the quotas are filled.
// once the quotas are filled iterate once more to find when the next one would be
// (also considering pre-emption reasons).
@@ -2460,11 +2713,13 @@
}
if (syncResult != null && syncResult.fullSyncRequested) {
- scheduleSyncOperation(new SyncOperation(syncOperation.account, syncOperation.userId,
- syncOperation.reason,
- syncOperation.syncSource, syncOperation.authority, new Bundle(), 0,
- syncOperation.backoff, syncOperation.delayUntil,
- syncOperation.allowParallelSyncs));
+ scheduleSyncOperation(
+ new SyncOperation(syncOperation.account, syncOperation.userId,
+ syncOperation.reason,
+ syncOperation.syncSource, syncOperation.authority, new Bundle(),
+ 0 /* delay */, 0 /* flex */,
+ syncOperation.backoff, syncOperation.delayUntil,
+ syncOperation.allowParallelSyncs));
}
// no need to schedule an alarm, as that will be done by our caller.
}
@@ -2637,6 +2892,8 @@
final boolean alarmIsActive = mAlarmScheduleTime != null;
final boolean needAlarm = alarmTime != Long.MAX_VALUE;
if (needAlarm) {
+ // Need the alarm if it's currently not set, or if our time is before the currently
+ // set time.
if (!alarmIsActive || alarmTime < mAlarmScheduleTime) {
shouldSet = true;
}
@@ -2644,7 +2901,7 @@
shouldCancel = alarmIsActive;
}
- // set or cancel the alarm as directed
+ // Set or cancel the alarm as directed.
ensureAlarmService();
if (shouldSet) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/java/com/android/server/content/SyncOperation.java
index eaad982..b688535 100644
--- a/services/java/com/android/server/content/SyncOperation.java
+++ b/services/java/com/android/server/content/SyncOperation.java
@@ -18,13 +18,18 @@
import android.accounts.Account;
import android.content.pm.PackageManager;
+import android.content.ComponentName;
import android.content.ContentResolver;
+import android.content.SyncRequest;
import android.os.Bundle;
import android.os.SystemClock;
+import android.util.Pair;
/**
* Value type that represents a sync operation.
- * @hide
+ * TODO: This is the class to flesh out with all the scheduling data - metered/unmetered,
+ * transfer-size, etc.
+ * {@hide}
*/
public class SyncOperation implements Comparable {
public static final int REASON_BACKGROUND_DATA_SETTINGS_CHANGED = -1;
@@ -32,7 +37,9 @@
public static final int REASON_SERVICE_CHANGED = -3;
public static final int REASON_PERIODIC = -4;
public static final int REASON_IS_SYNCABLE = -5;
+ /** Sync started because it has just been set to sync automatically. */
public static final int REASON_SYNC_AUTO = -6;
+ /** Sync started because master sync automatically has been set to true. */
public static final int REASON_MASTER_SYNC_AUTO = -7;
public static final int REASON_USER_START = -8;
@@ -47,75 +54,143 @@
"UserStart",
};
+ /** Account info to identify a SyncAdapter registered with the system. */
public final Account account;
+ /** Authority info to identify a SyncAdapter registered with the system. */
+ public final String authority;
+ /** Service to which this operation will bind to perform the sync. */
+ public final ComponentName service;
public final int userId;
public final int reason;
public int syncSource;
- public String authority;
public final boolean allowParallelSyncs;
public Bundle extras;
public final String key;
- public long earliestRunTime;
public boolean expedited;
public SyncStorageEngine.PendingOperation pendingOperation;
+ /** Elapsed real time in millis at which to run this sync. */
+ public long latestRunTime;
+ /** Set by the SyncManager in order to delay retries. */
public Long backoff;
+ /** Specified by the adapter to delay subsequent sync operations. */
public long delayUntil;
+ /**
+ * Elapsed real time in millis when this sync will be run.
+ * Depends on max(backoff, latestRunTime, and delayUntil).
+ */
public long effectiveRunTime;
+ /** Amount of time before {@link effectiveRunTime} from which this sync can run. */
+ public long flexTime;
public SyncOperation(Account account, int userId, int reason, int source, String authority,
- Bundle extras, long delayInMs, long backoff, long delayUntil,
- boolean allowParallelSyncs) {
+ Bundle extras, long runTimeFromNow, long flexTime, long backoff,
+ long delayUntil, boolean allowParallelSyncs) {
+ this.service = null;
this.account = account;
+ this.authority = authority;
this.userId = userId;
this.reason = reason;
this.syncSource = source;
- this.authority = authority;
this.allowParallelSyncs = allowParallelSyncs;
this.extras = new Bundle(extras);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_UPLOAD);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_MANUAL);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_EXPEDITED);
- removeFalseExtra(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
+ cleanBundle(this.extras);
this.delayUntil = delayUntil;
this.backoff = backoff;
final long now = SystemClock.elapsedRealtime();
- if (delayInMs < 0) {
+ // Check the extras bundle. Must occur after we set the internal bundle.
+ if (runTimeFromNow < 0 || isExpedited()) {
this.expedited = true;
- this.earliestRunTime = now;
+ this.latestRunTime = now;
+ this.flexTime = 0;
} else {
this.expedited = false;
- this.earliestRunTime = now + delayInMs;
+ this.latestRunTime = now + runTimeFromNow;
+ this.flexTime = flexTime;
}
updateEffectiveRunTime();
this.key = toKey();
}
- private void removeFalseExtra(String extraName) {
- if (!extras.getBoolean(extraName, false)) {
- extras.remove(extraName);
+ public SyncOperation(SyncRequest request, int userId, int reason, int source, long backoff,
+ long delayUntil, boolean allowParallelSyncs) {
+ if (request.hasAuthority()) {
+ Pair<Account, String> providerInfo = request.getProviderInfo();
+ this.account = providerInfo.first;
+ this.authority = providerInfo.second;
+ this.service = null;
+ } else {
+ this.service = request.getService();
+ this.account = null;
+ this.authority = null;
+ }
+ this.userId = userId;
+ this.reason = reason;
+ this.syncSource = source;
+ this.allowParallelSyncs = allowParallelSyncs;
+ this.extras = new Bundle(extras);
+ cleanBundle(this.extras);
+ this.delayUntil = delayUntil;
+ this.backoff = backoff;
+ final long now = SystemClock.elapsedRealtime();
+ if (request.isExpedited()) {
+ this.expedited = true;
+ this.latestRunTime = now;
+ this.flexTime = 0;
+ } else {
+ this.expedited = false;
+ this.latestRunTime = now + (request.getSyncRunTime() * 1000);
+ this.flexTime = request.getSyncFlexTime() * 1000;
+ }
+ updateEffectiveRunTime();
+ this.key = toKey();
+ }
+
+ /**
+ * Make sure the bundle attached to this SyncOperation doesn't have unnecessary
+ * flags set.
+ * @param bundle to clean.
+ */
+ private void cleanBundle(Bundle bundle) {
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_UPLOAD);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_MANUAL);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_EXPEDITED);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
+ removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_ALLOW_METERED);
+
+ // Remove Config data.
+ bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD);
+ bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD);
+ }
+
+ private void removeFalseExtra(Bundle bundle, String extraName) {
+ if (!bundle.getBoolean(extraName, false)) {
+ bundle.remove(extraName);
}
}
+ /** Only used to immediately reschedule a sync. */
SyncOperation(SyncOperation other) {
+ this.service = other.service;
this.account = other.account;
+ this.authority = other.authority;
this.userId = other.userId;
this.reason = other.reason;
this.syncSource = other.syncSource;
- this.authority = other.authority;
this.extras = new Bundle(other.extras);
this.expedited = other.expedited;
- this.earliestRunTime = SystemClock.elapsedRealtime();
+ this.latestRunTime = SystemClock.elapsedRealtime();
+ this.flexTime = 0L;
this.backoff = other.backoff;
- this.delayUntil = other.delayUntil;
this.allowParallelSyncs = other.allowParallelSyncs;
this.updateEffectiveRunTime();
this.key = toKey();
}
+ @Override
public String toString() {
return dump(null, true);
}
@@ -131,8 +206,8 @@
.append(authority)
.append(", ")
.append(SyncStorageEngine.SOURCES[syncSource])
- .append(", earliestRunTime ")
- .append(earliestRunTime);
+ .append(", latestRunTime ")
+ .append(latestRunTime);
if (expedited) {
sb.append(", EXPEDITED");
}
@@ -170,23 +245,38 @@
}
}
+ public boolean isMetered() {
+ return extras.getBoolean(ContentResolver.SYNC_EXTRAS_ALLOW_METERED, false);
+ }
+
public boolean isInitialization() {
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
}
public boolean isExpedited() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
+ return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false) || expedited;
}
public boolean ignoreBackoff() {
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
}
+ /** Changed in V3. */
private String toKey() {
StringBuilder sb = new StringBuilder();
- sb.append("authority: ").append(authority);
- sb.append(" account {name=" + account.name + ", user=" + userId + ", type=" + account.type
- + "}");
+ if (service == null) {
+ sb.append("authority: ").append(authority);
+ sb.append(" account {name=" + account.name + ", user=" + userId + ", type=" + account.type
+ + "}");
+ } else {
+ sb.append("service {package=" )
+ .append(service.getPackageName())
+ .append(" user=")
+ .append(userId)
+ .append(", class=")
+ .append(service.getClassName())
+ .append("}");
+ }
sb.append(" extras: ");
extrasToStringBuilder(extras, sb);
return sb.toString();
@@ -200,25 +290,40 @@
sb.append("]");
}
+ /**
+ * Update the effective run time of this Operation based on latestRunTime (specified at
+ * creation time of sync), delayUntil (specified by SyncAdapter), or backoff (specified by
+ * SyncManager on soft failures).
+ */
public void updateEffectiveRunTime() {
- effectiveRunTime = ignoreBackoff()
- ? earliestRunTime
- : Math.max(
- Math.max(earliestRunTime, delayUntil),
- backoff);
+ // Regardless of whether we're in backoff or honouring a delayUntil, we still incorporate
+ // the flex time provided by the developer.
+ effectiveRunTime = ignoreBackoff() ?
+ latestRunTime :
+ Math.max(Math.max(latestRunTime, delayUntil), backoff);
}
+ /**
+ * If two SyncOperation intervals are disjoint, the smaller is the interval that occurs before.
+ * If the intervals overlap, the two are considered equal.
+ */
+ @Override
public int compareTo(Object o) {
- SyncOperation other = (SyncOperation)o;
-
+ SyncOperation other = (SyncOperation) o;
if (expedited != other.expedited) {
return expedited ? -1 : 1;
}
-
- if (effectiveRunTime == other.effectiveRunTime) {
+ long x1 = effectiveRunTime - flexTime;
+ long y1 = effectiveRunTime;
+ long x2 = other.effectiveRunTime - other.flexTime;
+ long y2 = other.effectiveRunTime;
+ // Overlapping intervals.
+ if ((x1 <= y2 && x1 >= x2) || (x2 <= y1 && x2 >= x1)) {
return 0;
}
-
- return effectiveRunTime < other.effectiveRunTime ? -1 : 1;
+ if (x1 < x2 && y1 < x2) {
+ return -1;
+ }
+ return 1;
}
}
diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/java/com/android/server/content/SyncQueue.java
index 951e92c..6f3fe6e1 100644
--- a/services/java/com/android/server/content/SyncQueue.java
+++ b/services/java/com/android/server/content/SyncQueue.java
@@ -73,7 +73,7 @@
}
SyncOperation syncOperation = new SyncOperation(
op.account, op.userId, op.reason, op.syncSource, op.authority, op.extras,
- 0 /* delay */, backoff != null ? backoff.first : 0,
+ 0 /* delay */, 0 /* flex */, backoff != null ? backoff.first : 0,
mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
syncAdapterInfo.type.allowParallelSyncs());
syncOperation.expedited = op.expedited;
@@ -86,35 +86,40 @@
return add(operation, null /* this is not coming from the database */);
}
+ /**
+ * Adds a SyncOperation to the queue and creates a PendingOperation object to track that sync.
+ * If an operation is added that already exists, the existing operation is updated if the newly
+ * added operation occurs before (or the interval overlaps).
+ */
private boolean add(SyncOperation operation,
SyncStorageEngine.PendingOperation pop) {
- // - if an operation with the same key exists and this one should run earlier,
- // update the earliestRunTime of the existing to the new time
- // - if an operation with the same key exists and if this one should run
- // later, ignore it
- // - if no operation exists then add the new one
+ // If an operation with the same key exists and this one should run sooner/overlaps,
+ // replace the run interval of the existing operation with this new one.
+ // Complications: what if the existing operation is expedited but the new operation has an
+ // earlier run time? Will not be a problem for periodic syncs (no expedited flag), and for
+ // one-off syncs we only change it if the new sync is sooner.
final String operationKey = operation.key;
final SyncOperation existingOperation = mOperationsMap.get(operationKey);
if (existingOperation != null) {
boolean changed = false;
- if (existingOperation.expedited == operation.expedited) {
- final long newRunTime =
- Math.min(existingOperation.earliestRunTime, operation.earliestRunTime);
- if (existingOperation.earliestRunTime != newRunTime) {
- existingOperation.earliestRunTime = newRunTime;
- changed = true;
- }
- } else {
- if (operation.expedited) {
- existingOperation.expedited = true;
- changed = true;
- }
+ if (operation.compareTo(existingOperation) <= 0 ) {
+ existingOperation.expedited = operation.expedited;
+ long newRunTime =
+ Math.min(existingOperation.latestRunTime, operation.latestRunTime);
+ // Take smaller runtime.
+ existingOperation.latestRunTime = newRunTime;
+ // Take newer flextime.
+ existingOperation.flexTime = operation.flexTime;
+ changed = true;
}
return changed;
}
operation.pendingOperation = pop;
+ // Don't update the PendingOp if one already exists. This really is just a placeholder,
+ // no actual scheduling info is placed here.
+ // TODO: Change this to support service components.
if (operation.pendingOperation == null) {
pop = new SyncStorageEngine.PendingOperation(
operation.account, operation.userId, operation.reason, operation.syncSource,
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index c4dc575..0b99fca 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -18,6 +18,7 @@
import android.accounts.Account;
import android.accounts.AccountAndUser;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ISyncStatusObserver;
@@ -44,7 +45,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
-import com.android.server.content.SyncStorageEngine.AuthorityInfo;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -70,8 +70,8 @@
public class SyncStorageEngine extends Handler {
private static final String TAG = "SyncManager";
- private static final boolean DEBUG = false;
- private static final boolean DEBUG_FILE = false;
+ private static final boolean DEBUG = true;
+ private static final boolean DEBUG_FILE = true;
private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
private static final String XML_ATTR_LISTEN_FOR_TICKLES = "listen-for-tickles";
@@ -80,8 +80,15 @@
private static final String XML_ATTR_USER = "user";
private static final String XML_TAG_LISTEN_FOR_TICKLES = "listenForTickles";
+ /** Default time for a periodic sync. */
private static final long DEFAULT_POLL_FREQUENCY_SECONDS = 60 * 60 * 24; // One day
+ /** Percentage of period that is flex by default, if no flex is set. */
+ private static final double DEFAULT_FLEX_PERCENT_SYNC = 0.04;
+
+ /** Lower bound on sync time from which we assign a default flex time. */
+ private static final long DEFAULT_MIN_FLEX_ALLOWED_SECS = 5;
+
@VisibleForTesting
static final long MILLIS_IN_4WEEKS = 1000L * 60 * 60 * 24 * 7 * 4;
@@ -154,12 +161,13 @@
final int syncSource;
final String authority;
final Bundle extras; // note: read-only.
+ final ComponentName serviceName;
final boolean expedited;
int authorityId;
byte[] flatExtras;
- PendingOperation(Account account, int userId, int reason,int source,
+ PendingOperation(Account account, int userId, int reason, int source,
String authority, Bundle extras, boolean expedited) {
this.account = account;
this.userId = userId;
@@ -169,6 +177,7 @@
this.extras = extras != null ? new Bundle(extras) : extras;
this.expedited = expedited;
this.authorityId = -1;
+ this.serviceName = null;
}
PendingOperation(PendingOperation other) {
@@ -180,6 +189,7 @@
this.extras = other.extras;
this.authorityId = other.authorityId;
this.expedited = other.expedited;
+ this.serviceName = other.serviceName;
}
}
@@ -194,6 +204,7 @@
}
public static class AuthorityInfo {
+ final ComponentName service;
final Account account;
final int userId;
final String authority;
@@ -203,7 +214,7 @@
long backoffTime;
long backoffDelay;
long delayUntil;
- final ArrayList<Pair<Bundle, Long>> periodicSyncs;
+ final ArrayList<PeriodicSync> periodicSyncs;
/**
* Copy constructor for making deep-ish copies. Only the bundles stored
@@ -215,30 +226,70 @@
account = toCopy.account;
userId = toCopy.userId;
authority = toCopy.authority;
+ service = toCopy.service;
ident = toCopy.ident;
enabled = toCopy.enabled;
syncable = toCopy.syncable;
backoffTime = toCopy.backoffTime;
backoffDelay = toCopy.backoffDelay;
delayUntil = toCopy.delayUntil;
- periodicSyncs = new ArrayList<Pair<Bundle, Long>>();
- for (Pair<Bundle, Long> sync : toCopy.periodicSyncs) {
+ periodicSyncs = new ArrayList<PeriodicSync>();
+ for (PeriodicSync sync : toCopy.periodicSyncs) {
// Still not a perfect copy, because we are just copying the mappings.
- periodicSyncs.add(Pair.create(new Bundle(sync.first), sync.second));
+ periodicSyncs.add(new PeriodicSync(sync));
}
}
+ /**
+ * Create an authority with one periodic sync scheduled with an empty bundle and syncing
+ * every day. An empty bundle is considered equal to any other bundle see
+ * {@link PeriodicSync.syncExtrasEquals}.
+ * @param account Account that this authority syncs.
+ * @param userId which user this sync is registered for.
+ * @param userId user for which this authority is registered.
+ * @param ident id of this authority.
+ */
AuthorityInfo(Account account, int userId, String authority, int ident) {
this.account = account;
this.userId = userId;
this.authority = authority;
+ this.service = null;
this.ident = ident;
enabled = SYNC_ENABLED_DEFAULT;
syncable = -1; // default to "unknown"
backoffTime = -1; // if < 0 then we aren't in backoff mode
backoffDelay = -1; // if < 0 then we aren't in backoff mode
- periodicSyncs = new ArrayList<Pair<Bundle, Long>>();
- periodicSyncs.add(Pair.create(new Bundle(), DEFAULT_POLL_FREQUENCY_SECONDS));
+ periodicSyncs = new ArrayList<PeriodicSync>();
+ // Old version adds one periodic sync a day.
+ periodicSyncs.add(new PeriodicSync(account, authority,
+ new Bundle(),
+ DEFAULT_POLL_FREQUENCY_SECONDS,
+ calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
+ }
+
+ /**
+ * Create an authority with one periodic sync scheduled with an empty bundle and syncing
+ * every day using a sync service.
+ * @param cname sync service identifier.
+ * @param userId user for which this authority is registered.
+ * @param ident id of this authority.
+ */
+ AuthorityInfo(ComponentName cname, int userId, int ident) {
+ this.account = null;
+ this.userId = userId;
+ this.authority = null;
+ this.service = cname;
+ this.ident = ident;
+ // Sync service is always enabled.
+ enabled = true;
+ syncable = -1; // default to "unknown"
+ backoffTime = -1; // if < 0 then we aren't in backoff mode
+ backoffDelay = -1; // if < 0 then we aren't in backoff mode
+ periodicSyncs = new ArrayList<PeriodicSync>();
+ periodicSyncs.add(new PeriodicSync(account, authority,
+ new Bundle(),
+ DEFAULT_POLL_FREQUENCY_SECONDS,
+ calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
}
}
@@ -304,6 +355,10 @@
private final RemoteCallbackList<ISyncStatusObserver> mChangeListeners
= new RemoteCallbackList<ISyncStatusObserver>();
+ /** Reverse mapping for component name -> <userid -> authority id>. */
+ private final HashMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
+ new HashMap<ComponentName, SparseArray<AuthorityInfo>>();
+
private int mNextAuthorityId = 0;
// We keep 4 weeks of stats.
@@ -436,6 +491,28 @@
}
}
+ /**
+ * Figure out a reasonable flex time for cases where none is provided (old api calls).
+ * @param syncTimeSeconds requested sync time from now.
+ * @return amount of seconds before syncTimeSeconds that the sync can occur.
+ * I.e.
+ * earliest_sync_time = syncTimeSeconds - calculateDefaultFlexTime(syncTimeSeconds)
+ * The flex time is capped at a percentage of the {@link DEFAULT_POLL_FREQUENCY_SECONDS}.
+ */
+ public static long calculateDefaultFlexTime(long syncTimeSeconds) {
+ if (syncTimeSeconds < DEFAULT_MIN_FLEX_ALLOWED_SECS) {
+ // Small enough sync request time that we don't add flex time - developer probably
+ // wants to wait for an operation to occur before syncing so we honour the
+ // request time.
+ return 0L;
+ } else if (syncTimeSeconds < DEFAULT_POLL_FREQUENCY_SECONDS) {
+ return (long) (syncTimeSeconds * DEFAULT_FLEX_PERCENT_SYNC);
+ } else {
+ // Large enough sync request time that we cap the flex time.
+ return (long) (DEFAULT_POLL_FREQUENCY_SECONDS * DEFAULT_FLEX_PERCENT_SYNC);
+ }
+ }
+
private void reportChange(int which) {
ArrayList<ISyncStatusObserver> reports = null;
synchronized (mAuthorities) {
@@ -553,8 +630,8 @@
+ ", user " + userId + " -> " + syncable);
}
synchronized (mAuthorities) {
- AuthorityInfo authority = getOrCreateAuthorityLocked(account, userId, providerName, -1,
- false);
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(account, userId, providerName, -1, false);
if (authority.syncable == syncable) {
if (DEBUG) {
Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
@@ -689,62 +766,65 @@
}
}
- private void updateOrRemovePeriodicSync(Account account, int userId, String providerName,
- Bundle extras,
- long period, boolean add) {
- if (period <= 0) {
- period = 0;
- }
- if (extras == null) {
- extras = new Bundle();
- }
+ private void updateOrRemovePeriodicSync(PeriodicSync toUpdate, int userId, boolean add) {
if (DEBUG) {
- Log.v(TAG, "addOrRemovePeriodicSync: " + account + ", user " + userId
- + ", provider " + providerName
- + " -> period " + period + ", extras " + extras);
+ Log.v(TAG, "addOrRemovePeriodicSync: " + toUpdate.account + ", user " + userId
+ + ", provider " + toUpdate.authority
+ + " -> period " + toUpdate.period + ", extras " + toUpdate.extras);
}
synchronized (mAuthorities) {
+ if (toUpdate.period <= 0 && add) {
+ Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add);
+ }
+ if (toUpdate.extras == null) {
+ Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add);
+ }
try {
AuthorityInfo authority =
- getOrCreateAuthorityLocked(account, userId, providerName, -1, false);
+ getOrCreateAuthorityLocked(toUpdate.account, userId, toUpdate.authority,
+ -1, false);
if (add) {
- // add this periodic sync if one with the same extras doesn't already
- // exist in the periodicSyncs array
+ // add this periodic sync if an equivalent periodic doesn't already exist.
boolean alreadyPresent = false;
for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
- Pair<Bundle, Long> syncInfo = authority.periodicSyncs.get(i);
- final Bundle existingExtras = syncInfo.first;
- if (PeriodicSync.syncExtrasEquals(existingExtras, extras)) {
- if (syncInfo.second == period) {
+ PeriodicSync syncInfo = authority.periodicSyncs.get(i);
+ if (PeriodicSync.syncExtrasEquals(
+ toUpdate.extras,
+ syncInfo.extras)) {
+ if (toUpdate.period == syncInfo.period &&
+ toUpdate.flexTime == syncInfo.flexTime) {
+ // Absolutely the same.
return;
}
- authority.periodicSyncs.set(i, Pair.create(extras, period));
+ authority.periodicSyncs.set(i, new PeriodicSync(toUpdate));
alreadyPresent = true;
break;
}
}
- // if we added an entry to the periodicSyncs array also add an entry to
- // the periodic syncs status to correspond to it
+ // If we added an entry to the periodicSyncs array also add an entry to
+ // the periodic syncs status to correspond to it.
if (!alreadyPresent) {
- authority.periodicSyncs.add(Pair.create(extras, period));
+ authority.periodicSyncs.add(new PeriodicSync(toUpdate));
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
}
} else {
- // remove any periodic syncs that match the authority and extras
+ // Remove any periodic syncs that match the authority and extras.
SyncStatusInfo status = mSyncStatus.get(authority.ident);
boolean changed = false;
- Iterator<Pair<Bundle, Long>> iterator = authority.periodicSyncs.iterator();
+ Iterator<PeriodicSync> iterator = authority.periodicSyncs.iterator();
int i = 0;
while (iterator.hasNext()) {
- Pair<Bundle, Long> syncInfo = iterator.next();
- if (PeriodicSync.syncExtrasEquals(syncInfo.first, extras)) {
+ PeriodicSync syncInfo = iterator.next();
+ if (PeriodicSync.syncExtrasEquals(syncInfo.extras, toUpdate.extras)) {
iterator.remove();
changed = true;
- // if we removed an entry from the periodicSyncs array also
+ // If we removed an entry from the periodicSyncs array also
// remove the corresponding entry from the status
if (status != null) {
status.removePeriodicSyncTime(i);
+ } else {
+ Log.e(TAG, "Tried removing sync status on remove periodic sync but did not find it.");
}
} else {
i++;
@@ -763,16 +843,12 @@
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public void addPeriodicSync(Account account, int userId, String providerName, Bundle extras,
- long pollFrequency) {
- updateOrRemovePeriodicSync(account, userId, providerName, extras, pollFrequency,
- true /* add */);
+ public void addPeriodicSync(PeriodicSync toAdd, int userId) {
+ updateOrRemovePeriodicSync(toAdd, userId, true /* add */);
}
- public void removePeriodicSync(Account account, int userId, String providerName,
- Bundle extras) {
- updateOrRemovePeriodicSync(account, userId, providerName, extras, 0 /* period, ignored */,
- false /* remove */);
+ public void removePeriodicSync(PeriodicSync toRemove, int userId) {
+ updateOrRemovePeriodicSync(toRemove, userId, false /* remove */);
}
public List<PeriodicSync> getPeriodicSyncs(Account account, int userId, String providerName) {
@@ -781,9 +857,9 @@
AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
"getPeriodicSyncs");
if (authority != null) {
- for (Pair<Bundle, Long> item : authority.periodicSyncs) {
- syncs.add(new PeriodicSync(account, providerName, item.first,
- item.second));
+ for (PeriodicSync item : authority.periodicSyncs) {
+ // Copy and send out. Necessary for thread-safety although it's parceled.
+ syncs.add(new PeriodicSync(item));
}
}
}
@@ -866,7 +942,7 @@
op = new PendingOperation(op);
op.authorityId = authority.ident;
mPendingOperations.add(op);
- appendPendingOperationLocked(op);
+ writePendingOperationsLocked();
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = true;
@@ -876,6 +952,14 @@
return op;
}
+ /**
+ * Remove from list of pending operations. If successful, search through list for matching
+ * authorities. If there are no more pending syncs for the same authority/account/userid,
+ * update the SyncStatusInfo for that authority(authority here is the internal representation
+ * of a 'sync operation'.
+ * @param op
+ * @return
+ */
public boolean deleteFromPending(PendingOperation op) {
boolean res = false;
synchronized (mAuthorities) {
@@ -898,7 +982,7 @@
AuthorityInfo authority = getAuthorityLocked(op.account, op.userId, op.authority,
"deleteFromPending");
if (authority != null) {
- if (DEBUG) Log.v(TAG, "removing - " + authority);
+ if (DEBUG) Log.v(TAG, "removing - " + authority.toString());
final int N = mPendingOperations.size();
boolean morePending = false;
for (int i=0; i<N; i++) {
@@ -1391,6 +1475,65 @@
return authority;
}
+ /**
+ * Retrieve an authority, returning null if one does not exist.
+ *
+ * @param service The service name used for this sync.
+ * @param userId The user for whom this sync is scheduled.
+ * @param tag If non-null, this will be used in a log message if the
+ * requested authority does not exist.
+ */
+ private AuthorityInfo getAuthorityLocked(ComponentName service, int userId, String tag) {
+ AuthorityInfo authority = mServices.get(service).get(userId);
+ if (authority == null) {
+ if (tag != null) {
+ if (DEBUG) {
+ Log.v(TAG, tag + " No authority info found for " + service + " for user "
+ + userId);
+ }
+ }
+ return null;
+ }
+ return authority;
+ }
+
+ /**
+ * @param cname identifier for the service.
+ * @param userId for the syncs corresponding to this authority.
+ * @param ident unique identifier for authority. -1 for none.
+ * @param doWrite if true, update the accounts.xml file on the disk.
+ * @return the authority that corresponds to the provided sync service, creating it if none
+ * exists.
+ */
+ private AuthorityInfo getOrCreateAuthorityLocked(ComponentName cname, int userId, int ident,
+ boolean doWrite) {
+ SparseArray<AuthorityInfo> aInfo = mServices.get(cname);
+ if (aInfo == null) {
+ aInfo = new SparseArray<AuthorityInfo>();
+ mServices.put(cname, aInfo);
+ }
+ AuthorityInfo authority = aInfo.get(userId);
+ if (authority == null) {
+ if (ident < 0) {
+ ident = mNextAuthorityId;
+ mNextAuthorityId++;
+ doWrite = true;
+ }
+ if (DEBUG) {
+ Log.v(TAG, "created a new AuthorityInfo for " + cname.getPackageName()
+ + ", " + cname.getClassName()
+ + ", user: " + userId);
+ }
+ authority = new AuthorityInfo(cname, userId, ident);
+ aInfo.put(userId, authority);
+ mAuthorities.put(ident, authority);
+ if (doWrite) {
+ writeAccountInfoLocked();
+ }
+ }
+ return authority;
+ }
+
private AuthorityInfo getOrCreateAuthorityLocked(Account accountName, int userId,
String authorityName, int ident, boolean doWrite) {
AccountAndUser au = new AccountAndUser(accountName, userId);
@@ -1441,22 +1584,20 @@
* authority id and target periodic sync
*/
public void setPeriodicSyncTime(
- int authorityId, Pair<Bundle, Long> targetPeriodicSync, long when) {
+ int authorityId, PeriodicSync targetPeriodicSync, long when) {
boolean found = false;
final AuthorityInfo authorityInfo;
synchronized (mAuthorities) {
authorityInfo = mAuthorities.get(authorityId);
for (int i = 0; i < authorityInfo.periodicSyncs.size(); i++) {
- Pair<Bundle, Long> periodicSync = authorityInfo.periodicSyncs.get(i);
- if (PeriodicSync.syncExtrasEquals(periodicSync.first, targetPeriodicSync.first)
- && periodicSync.second == targetPeriodicSync.second) {
+ PeriodicSync periodicSync = authorityInfo.periodicSyncs.get(i);
+ if (targetPeriodicSync.equals(periodicSync)) {
mSyncStatus.get(authorityId).setPeriodicSyncTime(i, when);
found = true;
break;
}
}
}
-
if (!found) {
Log.w(TAG, "Ignoring setPeriodicSyncTime request for a sync that does not exist. " +
"Authority: " + authorityInfo.authority);
@@ -1494,6 +1635,7 @@
synchronized (mAuthorities) {
mAuthorities.clear();
mAccounts.clear();
+ mServices.clear();
mPendingOperations.clear();
mSyncStatus.clear();
mSyncHistory.clear();
@@ -1555,7 +1697,7 @@
mMasterSyncAutomatically.put(0, listen == null || Boolean.parseBoolean(listen));
eventType = parser.next();
AuthorityInfo authority = null;
- Pair<Bundle, Long> periodicSync = null;
+ PeriodicSync periodicSync = null;
do {
if (eventType == XmlPullParser.START_TAG) {
tagName = parser.getName();
@@ -1575,7 +1717,7 @@
}
} else if (parser.getDepth() == 4 && periodicSync != null) {
if ("extra".equals(tagName)) {
- parseExtra(parser, periodicSync);
+ parseExtra(parser, periodicSync.extras);
}
}
}
@@ -1669,8 +1811,7 @@
AuthorityInfo authority = null;
int id = -1;
try {
- id = Integer.parseInt(parser.getAttributeValue(
- null, "id"));
+ id = Integer.parseInt(parser.getAttributeValue(null, "id"));
} catch (NumberFormatException e) {
Log.e(TAG, "error parsing the id of the authority", e);
} catch (NullPointerException e) {
@@ -1683,6 +1824,8 @@
String accountName = parser.getAttributeValue(null, "account");
String accountType = parser.getAttributeValue(null, "type");
String user = parser.getAttributeValue(null, XML_ATTR_USER);
+ String packageName = parser.getAttributeValue(null, "package");
+ String className = parser.getAttributeValue(null, "class");
int userId = user == null ? 0 : Integer.parseInt(user);
if (accountType == null) {
accountType = "com.google";
@@ -1695,12 +1838,19 @@
+ " enabled=" + enabled
+ " syncable=" + syncable);
if (authority == null) {
- if (DEBUG_FILE) Log.v(TAG, "Creating entry");
- authority = getOrCreateAuthorityLocked(
- new Account(accountName, accountType), userId, authorityName, id, false);
+ if (DEBUG_FILE) {
+ Log.v(TAG, "Creating entry");
+ }
+ if (accountName != null && accountType != null) {
+ authority = getOrCreateAuthorityLocked(
+ new Account(accountName, accountType), userId, authorityName, id, false);
+ } else {
+ authority = getOrCreateAuthorityLocked(
+ new ComponentName(packageName, className), userId, id, false);
+ }
// If the version is 0 then we are upgrading from a file format that did not
// know about periodic syncs. In that case don't clear the list since we
- // want the default, which is a daily periodioc sync.
+ // want the default, which is a daily periodic sync.
// Otherwise clear out this default list since we will populate it later with
// the periodic sync descriptions that are read from the configuration file.
if (version > 0) {
@@ -1722,14 +1872,18 @@
+ " syncable=" + syncable);
}
}
-
return authority;
}
- private Pair<Bundle, Long> parsePeriodicSync(XmlPullParser parser, AuthorityInfo authority) {
- Bundle extras = new Bundle();
+ /**
+ * Parse a periodic sync from accounts.xml. Sets the bundle to be empty.
+ */
+ private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authority) {
+ Bundle extras = new Bundle(); // Gets filled in later.
String periodValue = parser.getAttributeValue(null, "period");
+ String flexValue = parser.getAttributeValue(null, "flex");
final long period;
+ long flextime;
try {
period = Long.parseLong(periodValue);
} catch (NumberFormatException e) {
@@ -1739,14 +1893,24 @@
Log.e(TAG, "the period of a periodic sync is null", e);
return null;
}
- final Pair<Bundle, Long> periodicSync = Pair.create(extras, period);
+ try {
+ flextime = Long.parseLong(flexValue);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue);
+ flextime = calculateDefaultFlexTime(period);
+ } catch (NullPointerException expected) {
+ flextime = calculateDefaultFlexTime(period);
+ Log.d(TAG, "No flex time specified for this sync, using a default. period: "
+ + period + " flex: " + flextime);
+ }
+ final PeriodicSync periodicSync =
+ new PeriodicSync(authority.account, authority.authority, extras,
+ period, flextime);
authority.periodicSyncs.add(periodicSync);
-
return periodicSync;
}
- private void parseExtra(XmlPullParser parser, Pair<Bundle, Long> periodicSync) {
- final Bundle extras = periodicSync.first;
+ private void parseExtra(XmlPullParser parser, Bundle extras) {
String name = parser.getAttributeValue(null, "name");
String type = parser.getAttributeValue(null, "type");
String value1 = parser.getAttributeValue(null, "value1");
@@ -1806,62 +1970,37 @@
}
final int N = mAuthorities.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
AuthorityInfo authority = mAuthorities.valueAt(i);
out.startTag(null, "authority");
out.attribute(null, "id", Integer.toString(authority.ident));
- out.attribute(null, "account", authority.account.name);
out.attribute(null, XML_ATTR_USER, Integer.toString(authority.userId));
- out.attribute(null, "type", authority.account.type);
- out.attribute(null, "authority", authority.authority);
out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(authority.enabled));
+ if (authority.service == null) {
+ out.attribute(null, "account", authority.account.name);
+ out.attribute(null, "type", authority.account.type);
+ out.attribute(null, "authority", authority.authority);
+ } else {
+ out.attribute(null, "package", authority.service.getPackageName());
+ out.attribute(null, "class", authority.service.getClassName());
+ }
if (authority.syncable < 0) {
out.attribute(null, "syncable", "unknown");
} else {
out.attribute(null, "syncable", Boolean.toString(authority.syncable != 0));
}
- for (Pair<Bundle, Long> periodicSync : authority.periodicSyncs) {
+ for (PeriodicSync periodicSync : authority.periodicSyncs) {
out.startTag(null, "periodicSync");
- out.attribute(null, "period", Long.toString(periodicSync.second));
- final Bundle extras = periodicSync.first;
- for (String key : extras.keySet()) {
- out.startTag(null, "extra");
- out.attribute(null, "name", key);
- final Object value = extras.get(key);
- if (value instanceof Long) {
- out.attribute(null, "type", "long");
- out.attribute(null, "value1", value.toString());
- } else if (value instanceof Integer) {
- out.attribute(null, "type", "integer");
- out.attribute(null, "value1", value.toString());
- } else if (value instanceof Boolean) {
- out.attribute(null, "type", "boolean");
- out.attribute(null, "value1", value.toString());
- } else if (value instanceof Float) {
- out.attribute(null, "type", "float");
- out.attribute(null, "value1", value.toString());
- } else if (value instanceof Double) {
- out.attribute(null, "type", "double");
- out.attribute(null, "value1", value.toString());
- } else if (value instanceof String) {
- out.attribute(null, "type", "string");
- out.attribute(null, "value1", value.toString());
- } else if (value instanceof Account) {
- out.attribute(null, "type", "account");
- out.attribute(null, "value1", ((Account)value).name);
- out.attribute(null, "value2", ((Account)value).type);
- }
- out.endTag(null, "extra");
- }
+ out.attribute(null, "period", Long.toString(periodicSync.period));
+ out.attribute(null, "flex", Long.toString(periodicSync.flexTime));
+ final Bundle extras = periodicSync.extras;
+ extrasToXml(out, extras);
out.endTag(null, "periodicSync");
}
out.endTag(null, "authority");
}
-
out.endTag(null, "accounts");
-
out.endDocument();
-
mAccountInfoFile.finishWrite(fos);
} catch (java.io.IOException e1) {
Log.w(TAG, "Error writing accounts", e1);
@@ -2072,7 +2211,7 @@
}
}
- public static final int PENDING_OPERATION_VERSION = 3;
+ public static final int PENDING_OPERATION_VERSION = 4;
/**
* Read all pending operations back in to the initial engine state.
@@ -2080,128 +2219,162 @@
private void readPendingOperationsLocked() {
if (DEBUG_FILE) Log.v(TAG, "Reading " + mPendingFile.getBaseFile());
try {
- byte[] data = mPendingFile.readFully();
- Parcel in = Parcel.obtain();
- in.unmarshall(data, 0, data.length);
- in.setDataPosition(0);
- final int SIZE = in.dataSize();
- while (in.dataPosition() < SIZE) {
- int version = in.readInt();
- if (version != PENDING_OPERATION_VERSION && version != 1) {
- Log.w(TAG, "Unknown pending operation version "
- + version + "; dropping all ops");
- break;
- }
- int authorityId = in.readInt();
- int syncSource = in.readInt();
- byte[] flatExtras = in.createByteArray();
- boolean expedited;
- if (version == PENDING_OPERATION_VERSION) {
- expedited = in.readInt() != 0;
- } else {
- expedited = false;
- }
- int reason = in.readInt();
- AuthorityInfo authority = mAuthorities.get(authorityId);
- if (authority != null) {
- Bundle extras;
- if (flatExtras != null) {
- extras = unflattenBundle(flatExtras);
- } else {
- // if we are unable to parse the extras for whatever reason convert this
- // to a regular sync by creating an empty extras
- extras = new Bundle();
- }
- PendingOperation op = new PendingOperation(
- authority.account, authority.userId, reason, syncSource,
- authority.authority, extras, expedited);
- op.authorityId = authorityId;
- op.flatExtras = flatExtras;
- if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + op.account
- + " auth=" + op.authority
- + " src=" + op.syncSource
- + " reason=" + op.reason
- + " expedited=" + op.expedited
- + " extras=" + op.extras);
- mPendingOperations.add(op);
- }
- }
- } catch (java.io.IOException e) {
- Log.i(TAG, "No initial pending operations");
- }
- }
-
- private void writePendingOperationLocked(PendingOperation op, Parcel out) {
- out.writeInt(PENDING_OPERATION_VERSION);
- out.writeInt(op.authorityId);
- out.writeInt(op.syncSource);
- if (op.flatExtras == null && op.extras != null) {
- op.flatExtras = flattenBundle(op.extras);
- }
- out.writeByteArray(op.flatExtras);
- out.writeInt(op.expedited ? 1 : 0);
- out.writeInt(op.reason);
- }
-
- /**
- * Write all currently pending ops to the pending ops file.
- */
- private void writePendingOperationsLocked() {
- final int N = mPendingOperations.size();
- FileOutputStream fos = null;
- try {
- if (N == 0) {
- if (DEBUG_FILE) Log.v(TAG, "Truncating " + mPendingFile.getBaseFile());
- mPendingFile.truncate();
- return;
- }
-
- if (DEBUG_FILE) Log.v(TAG, "Writing new " + mPendingFile.getBaseFile());
- fos = mPendingFile.startWrite();
-
- Parcel out = Parcel.obtain();
- for (int i=0; i<N; i++) {
- PendingOperation op = mPendingOperations.get(i);
- writePendingOperationLocked(op, out);
- }
- fos.write(out.marshall());
- out.recycle();
-
- mPendingFile.finishWrite(fos);
- } catch (java.io.IOException e1) {
- Log.w(TAG, "Error writing pending operations", e1);
- if (fos != null) {
- mPendingFile.failWrite(fos);
- }
- }
- }
-
- /**
- * Append the given operation to the pending ops file; if unable to,
- * write all pending ops.
- */
- private void appendPendingOperationLocked(PendingOperation op) {
- if (DEBUG_FILE) Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
- FileOutputStream fos = null;
- try {
- fos = mPendingFile.openAppend();
- } catch (java.io.IOException e) {
- if (DEBUG_FILE) Log.v(TAG, "Failed append; writing full file");
- writePendingOperationsLocked();
- return;
- }
-
- try {
- Parcel out = Parcel.obtain();
- writePendingOperationLocked(op, out);
- fos.write(out.marshall());
- out.recycle();
- } catch (java.io.IOException e1) {
- Log.w(TAG, "Error writing pending operations", e1);
- } finally {
+ readPendingAsXml();
+ } catch (XmlPullParserException e) {
+ Log.d(TAG, "Error parsing pending as xml, trying as parcel.");
try {
- fos.close();
- } catch (java.io.IOException e2) {
+ readPendingAsParcelled();
+ } catch (java.io.IOException e1) {
+ Log.i(TAG, "No initial pending operations");
+ }
+ }
+ }
+
+ private void readPendingAsXml() throws XmlPullParserException {
+ FileInputStream fis = null;
+ try {
+ Log.v(TAG, "is this thing on");
+ fis = mPendingFile.openRead();
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, null);
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.START_TAG &&
+ eventType != XmlPullParser.END_DOCUMENT) {
+ eventType = parser.next();
+ Log.v(TAG, "go: " + eventType);
+ }
+ if (eventType == XmlPullParser.END_DOCUMENT) return;
+
+ String tagName = parser.getName();
+ if (DEBUG_FILE) {
+ Log.v(TAG, "got " + tagName);
+ }
+ if ("pending".equals(tagName)) {
+ int version = -1;
+ String versionString = parser.getAttributeValue(null, "version");
+ if (versionString == null ||
+ Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) {
+ Log.w(TAG, "Unknown pending operation version "
+ + version + "; trying to read as binary.");
+ throw new XmlPullParserException("Unknown version.");
+ }
+ eventType = parser.next();
+ PendingOperation pop = null;
+ do {
+ if (DEBUG_FILE) {
+ Log.v(TAG, "parsing xml file");
+ }
+ if (eventType == XmlPullParser.START_TAG) {
+ try {
+ tagName = parser.getName();
+ if (parser.getDepth() == 2 && "op".equals(tagName)) {
+ int authorityId = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_AUTHORITYID));
+ boolean expedited = Boolean.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_EXPEDITED));
+ int syncSource = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_SOURCE));
+ int reason = Integer.valueOf(parser.getAttributeValue(
+ null, XML_ATTR_REASON));
+ AuthorityInfo authority = mAuthorities.get(authorityId);
+ if (DEBUG_FILE) {
+ Log.v(TAG, authorityId + " " + expedited + " " + syncSource + " " + reason);
+ }
+ if (authority != null) {
+ pop = new PendingOperation(
+ authority.account, authority.userId, reason, syncSource,
+ authority.authority, new Bundle(), expedited);
+ pop.authorityId = authorityId;
+ pop.flatExtras = null; // No longer used.
+ mPendingOperations.add(pop);
+ if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + pop.account
+ + " auth=" + pop.authority
+ + " src=" + pop.syncSource
+ + " reason=" + pop.reason
+ + " expedited=" + pop.expedited);
+ } else {
+ // Skip non-existent authority;
+ pop = null;
+ if (DEBUG_FILE) {
+ Log.v(TAG, "No authority found for " + authorityId
+ + ", skipping");
+ }
+ }
+ } else if (parser.getDepth() == 3 &&
+ pop != null &&
+ "extra".equals(tagName)) {
+ parseExtra(parser, pop.extras);
+ }
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "Invalid data in xml file.", e);
+ }
+ }
+ eventType = parser.next();
+ } while(eventType != XmlPullParser.END_DOCUMENT);
+ }
+ } catch (java.io.IOException e) {
+ if (fis == null) Log.i(TAG, "No initial pending operations.");
+ else Log.w(TAG, "Error reading pending data.", e);
+ return;
+ } finally {
+ if (DEBUG_FILE) Log.v(TAG, "Done reading pending ops");
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (java.io.IOException e1) {}
+ }
+ }
+ }
+ /**
+ * Old format of reading pending.bin as a parcelled file. Replaced in lieu of JSON because
+ * persisting parcels is unsafe.
+ * @throws java.io.IOException
+ */
+ private void readPendingAsParcelled() throws java.io.IOException {
+ byte[] data = mPendingFile.readFully();
+ Parcel in = Parcel.obtain();
+ in.unmarshall(data, 0, data.length);
+ in.setDataPosition(0);
+ final int SIZE = in.dataSize();
+ while (in.dataPosition() < SIZE) {
+ int version = in.readInt();
+ if (version != 3 && version != 1) {
+ Log.w(TAG, "Unknown pending operation version "
+ + version + "; dropping all ops");
+ break;
+ }
+ int authorityId = in.readInt();
+ int syncSource = in.readInt();
+ byte[] flatExtras = in.createByteArray();
+ boolean expedited;
+ if (version == PENDING_OPERATION_VERSION) {
+ expedited = in.readInt() != 0;
+ } else {
+ expedited = false;
+ }
+ int reason = in.readInt();
+ AuthorityInfo authority = mAuthorities.get(authorityId);
+ if (authority != null) {
+ Bundle extras;
+ if (flatExtras != null) {
+ extras = unflattenBundle(flatExtras);
+ } else {
+ // if we are unable to parse the extras for whatever reason convert this
+ // to a regular sync by creating an empty extras
+ extras = new Bundle();
+ }
+ PendingOperation op = new PendingOperation(
+ authority.account, authority.userId, reason, syncSource,
+ authority.authority, extras, expedited);
+ op.authorityId = authorityId;
+ op.flatExtras = flatExtras;
+ if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + op.account
+ + " auth=" + op.authority
+ + " src=" + op.syncSource
+ + " reason=" + op.reason
+ + " expedited=" + op.expedited
+ + " extras=" + op.extras);
+ mPendingOperations.add(op);
}
}
}
@@ -2235,6 +2408,115 @@
return bundle;
}
+ private static final String XML_ATTR_AUTHORITYID = "authority_id";
+ private static final String XML_ATTR_SOURCE = "source";
+ private static final String XML_ATTR_EXPEDITED = "expedited";
+ private static final String XML_ATTR_REASON = "reason";
+ /**
+ * Write all currently pending ops to the pending ops file. TODO: Change this from xml
+ * so that we can append to this file as before.
+ */
+ private void writePendingOperationsLocked() {
+ final int N = mPendingOperations.size();
+ FileOutputStream fos = null;
+ try {
+ if (N == 0) {
+ if (DEBUG_FILE) Log.v(TAG, "Truncating " + mPendingFile.getBaseFile());
+ mPendingFile.truncate();
+ return;
+ }
+ if (DEBUG_FILE) Log.v(TAG, "Writing new " + mPendingFile.getBaseFile());
+ fos = mPendingFile.startWrite();
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(fos, "utf-8");
+ out.startDocument(null, true);
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ out.startTag(null, "pending");
+ out.attribute(null, "version", Integer.toString(PENDING_OPERATION_VERSION));
+
+ for (int i = 0; i < N; i++) {
+ PendingOperation pop = mPendingOperations.get(i);
+ out.startTag(null, "op");
+ out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
+ out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
+ out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
+ out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
+ extrasToXml(out, pop.extras);
+ out.endTag(null, "op");
+ }
+ out.endTag(null, "pending");
+ out.endDocument();
+ mPendingFile.finishWrite(fos);
+ } catch (java.io.IOException e1) {
+ Log.w(TAG, "Error writing pending operations", e1);
+ if (fos != null) {
+ mPendingFile.failWrite(fos);
+ }
+ }
+ }
+
+ private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException {
+ for (String key : extras.keySet()) {
+ out.startTag(null, "extra");
+ out.attribute(null, "name", key);
+ final Object value = extras.get(key);
+ if (value instanceof Long) {
+ out.attribute(null, "type", "long");
+ out.attribute(null, "value1", value.toString());
+ } else if (value instanceof Integer) {
+ out.attribute(null, "type", "integer");
+ out.attribute(null, "value1", value.toString());
+ } else if (value instanceof Boolean) {
+ out.attribute(null, "type", "boolean");
+ out.attribute(null, "value1", value.toString());
+ } else if (value instanceof Float) {
+ out.attribute(null, "type", "float");
+ out.attribute(null, "value1", value.toString());
+ } else if (value instanceof Double) {
+ out.attribute(null, "type", "double");
+ out.attribute(null, "value1", value.toString());
+ } else if (value instanceof String) {
+ out.attribute(null, "type", "string");
+ out.attribute(null, "value1", value.toString());
+ } else if (value instanceof Account) {
+ out.attribute(null, "type", "account");
+ out.attribute(null, "value1", ((Account)value).name);
+ out.attribute(null, "value2", ((Account)value).type);
+ }
+ out.endTag(null, "extra");
+ }
+ }
+
+// /**
+// * Update the pending ops file, if e
+// */
+// private void appendPendingOperationLocked(PendingOperation op) {
+// if (DEBUG_FILE) Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
+// FileOutputStream fos = null;
+// try {
+// fos = mPendingFile.openAppend();
+// } catch (java.io.IOException e) {
+// if (DEBUG_FILE) Log.v(TAG, "Failed append; writing full file");
+// writePendingOperationsLocked();
+// return;
+// }
+//
+// try {
+// Parcel out = Parcel.obtain();
+// writePendingOperationLocked(op, out);
+// fos.write(out.marshall());
+// out.recycle();
+// } catch (java.io.IOException e1) {
+// Log.w(TAG, "Error writing pending operations", e1);
+// } finally {
+// try {
+// fos.close();
+// } catch (java.io.IOException e2) {
+// }
+// }
+// }
+
private void requestSync(Account account, int userId, int reason, String authority,
Bundle extras) {
// If this is happening in the system process, then call the syncrequest listener
@@ -2330,4 +2612,18 @@
}
}
}
+
+ /**
+ * Dump state of PendingOperations.
+ */
+ public void dumpPendingOperations(StringBuilder sb) {
+ sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n");
+ for (PendingOperation pop : mPendingOperations) {
+ sb.append("(" + pop.account)
+ .append(", " + pop.userId)
+ .append(", " + pop.authority)
+ .append(", " + pop.extras)
+ .append(")\n");
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index f2772c8..37176d6 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.content;
import android.accounts.Account;
+import android.content.ContentResolver;
import android.os.Bundle;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -48,7 +49,8 @@
SyncOperation.REASON_PERIODIC,
"authority1",
b1,
- 100,
+ 100, /* run time from now*/
+ 10, /* flex */
1000,
10000,
false);
@@ -60,6 +62,7 @@
"authority1",
b1,
200,
+ 20,
2000,
20000,
false);
@@ -71,6 +74,7 @@
"authority2",
b1,
100,
+ 10,
1000,
10000,
false);
@@ -82,6 +86,7 @@
"authority1",
b1,
100,
+ 10,
1000,
10000,
false);
@@ -93,6 +98,7 @@
"authority1",
b2,
100,
+ 10,
1000,
10000,
false);
@@ -102,4 +108,38 @@
assertNotSame(op1.key, op4.key);
assertNotSame(op1.key, op5.key);
}
+
+ @SmallTest
+ public void testCompareTo() {
+ Account dummy = new Account("account1", "type1");
+ Bundle b1 = new Bundle();
+ final long unimportant = 0L;
+ long soon = 1000;
+ long soonFlex = 50;
+ long after = 1500;
+ long afterFlex = 100;
+ SyncOperation op1 = new SyncOperation(dummy, 0, 0, SyncOperation.REASON_PERIODIC,
+ "authority1", b1, soon, soonFlex, unimportant, unimportant, true);
+
+ // Interval disjoint from and after op1.
+ SyncOperation op2 = new SyncOperation(dummy, 0, 0, SyncOperation.REASON_PERIODIC,
+ "authority1", b1, after, afterFlex, unimportant, unimportant, true);
+
+ // Interval equivalent to op1, but expedited.
+ Bundle b2 = new Bundle();
+ b2.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ SyncOperation op3 = new SyncOperation(dummy, 0, 0, 0,
+ "authority1", b2, soon, soonFlex, unimportant, unimportant, true);
+
+ // Interval overlaps but not equivalent to op1.
+ SyncOperation op4 = new SyncOperation(dummy, 0, 0, SyncOperation.REASON_PERIODIC,
+ "authority1", b1, soon + 100, soonFlex + 100, unimportant, unimportant, true);
+
+ assertTrue(op1.compareTo(op2) == -1);
+ assertTrue("less than not transitive.", op2.compareTo(op1) == 1);
+ assertTrue(op1.compareTo(op3) == 1);
+ assertTrue("greater than not transitive. ", op3.compareTo(op1) == -1);
+ assertTrue("overlapping intervals not the same.", op1.compareTo(op4) == 0);
+ assertTrue("equality not transitive.", op4.compareTo(op1) == 0);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index 8b00f2c2..dff6661 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -22,6 +22,7 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.PeriodicSync;
+import android.content.res.Resources;
import android.os.Bundle;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
@@ -39,10 +40,31 @@
public class SyncStorageEngineTest extends AndroidTestCase {
+ protected Account account1;
+ protected String authority1 = "testprovider";
+ protected Bundle defaultBundle;
+ protected final int DEFAULT_USER = 0;
+
+ MockContentResolver mockResolver;
+ SyncStorageEngine engine;
+
private File getSyncDir() {
return new File(new File(getContext().getFilesDir(), "system"), "sync");
}
+ @Override
+ public void setUp() {
+ account1 = new Account("a@example.com", "example.type");
+ // Default bundle.
+ defaultBundle = new Bundle();
+ defaultBundle.putInt("int_key", 0);
+ defaultBundle.putString("string_key", "hello");
+ // Set up storage engine.
+ mockResolver = new MockContentResolver();
+ engine = SyncStorageEngine.newTestInstance(
+ new TestContext(mockResolver, getContext()));
+ }
+
/**
* Test that we handle the case of a history row being old enough to purge before the
* correcponding sync is finished. This can happen if the clock changes while we are syncing.
@@ -68,7 +90,25 @@
}
/**
- * Test that we can create, remove and retrieve periodic syncs
+ * Test persistence of pending operations.
+ */
+ @MediumTest
+ public void testPending() throws Exception {
+ SyncStorageEngine.PendingOperation pop =
+ new SyncStorageEngine.PendingOperation(account1, DEFAULT_USER,
+ SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_LOCAL,
+ authority1, defaultBundle, false);
+
+ engine.insertIntoPending(pop);
+ // Force engine to read from disk.
+ engine.clearAndReadState();
+
+ assert(engine.getPendingOperationCount() == 1);
+ }
+
+ /**
+ * Test that we can create, remove and retrieve periodic syncs. Backwards compatibility -
+ * periodic syncs with no flex time are no longer used.
*/
@MediumTest
public void testPeriodics() throws Exception {
@@ -87,22 +127,19 @@
PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2);
PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2);
- MockContentResolver mockResolver = new MockContentResolver();
-
- SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
- new TestContext(mockResolver, getContext()));
+
removePeriodicSyncs(engine, account1, 0, authority);
removePeriodicSyncs(engine, account2, 0, authority);
removePeriodicSyncs(engine, account1, 1, authority);
// this should add two distinct periodic syncs for account1 and one for account2
- engine.addPeriodicSync(sync1.account, 0, sync1.authority, sync1.extras, sync1.period);
- engine.addPeriodicSync(sync2.account, 0, sync2.authority, sync2.extras, sync2.period);
- engine.addPeriodicSync(sync3.account, 0, sync3.authority, sync3.extras, sync3.period);
- engine.addPeriodicSync(sync4.account, 0, sync4.authority, sync4.extras, sync4.period);
+ engine.addPeriodicSync(sync1, 0);
+ engine.addPeriodicSync(sync2, 0);
+ engine.addPeriodicSync(sync3, 0);
+ engine.addPeriodicSync(sync4, 0);
// add a second user
- engine.addPeriodicSync(sync2.account, 1, sync2.authority, sync2.extras, sync2.period);
+ engine.addPeriodicSync(sync2, 1);
List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
@@ -111,7 +148,7 @@
assertEquals(sync1, syncs.get(0));
assertEquals(sync3, syncs.get(1));
- engine.removePeriodicSync(sync1.account, 0, sync1.authority, sync1.extras);
+ engine.removePeriodicSync(sync1, 0);
syncs = engine.getPeriodicSyncs(account1, 0, authority);
assertEquals(1, syncs.size());
@@ -126,13 +163,72 @@
assertEquals(sync2, syncs.get(0));
}
- private void removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId,
- String authority) {
- engine.setIsSyncable(account, userId, authority,
- engine.getIsSyncable(account, 0, authority));
+ /**
+ * Test that we can create, remove and retrieve periodic syncs with a provided flex time.
+ */
+ @MediumTest
+ public void testPeriodicsV2() throws Exception {
+ final Account account1 = new Account("a@example.com", "example.type");
+ final Account account2 = new Account("b@example.com", "example.type.2");
+ final String authority = "testprovider";
+ final Bundle extras1 = new Bundle();
+ extras1.putString("a", "1");
+ final Bundle extras2 = new Bundle();
+ extras2.putString("a", "2");
+ final int period1 = 200;
+ final int period2 = 1000;
+ final int flex1 = 10;
+ final int flex2 = 100;
+
+ PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1, flex1);
+ PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1, flex1);
+ PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2, flex2);
+ PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2, flex2);
+
+ MockContentResolver mockResolver = new MockContentResolver();
+
+ SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
+ new TestContext(mockResolver, getContext()));
+
+ removePeriodicSyncs(engine, account1, 0, authority);
+ removePeriodicSyncs(engine, account2, 0, authority);
+ removePeriodicSyncs(engine, account1, 1, authority);
+
+ // This should add two distinct periodic syncs for account1 and one for account2
+ engine.addPeriodicSync(sync1, 0);
+ engine.addPeriodicSync(sync2, 0);
+ engine.addPeriodicSync(sync3, 0); // Should edit sync2 and update the period.
+ engine.addPeriodicSync(sync4, 0);
+ // add a second user
+ engine.addPeriodicSync(sync2, 1);
+
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
+
+ assertEquals(2, syncs.size());
+
+ assertEquals(sync1, syncs.get(0));
+ assertEquals(sync3, syncs.get(1));
+
+ engine.removePeriodicSync(sync1, 0);
+
+ syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ assertEquals(1, syncs.size());
+ assertEquals(sync3, syncs.get(0));
+
+ syncs = engine.getPeriodicSyncs(account2, 0, authority);
+ assertEquals(1, syncs.size());
+ assertEquals(sync4, syncs.get(0));
+
+ syncs = engine.getPeriodicSyncs(sync2.account, 1, sync2.authority);
+ assertEquals(1, syncs.size());
+ assertEquals(sync2, syncs.get(0));
+ }
+
+ private void removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId, String authority) {
+ engine.setIsSyncable(account, userId, authority, engine.getIsSyncable(account, 0, authority));
List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, userId, authority);
for (PeriodicSync sync : syncs) {
- engine.removePeriodicSync(sync.account, userId, sync.authority, sync.extras);
+ engine.removePeriodicSync(sync, userId);
}
}
@@ -154,12 +250,14 @@
extras2.putParcelable("g", account1);
final int period1 = 200;
final int period2 = 1000;
+ final int flex1 = 10;
+ final int flex2 = 100;
- PeriodicSync sync1 = new PeriodicSync(account1, authority1, extras1, period1);
- PeriodicSync sync2 = new PeriodicSync(account1, authority1, extras2, period1);
- PeriodicSync sync3 = new PeriodicSync(account1, authority2, extras1, period1);
- PeriodicSync sync4 = new PeriodicSync(account1, authority2, extras2, period2);
- PeriodicSync sync5 = new PeriodicSync(account2, authority1, extras1, period1);
+ PeriodicSync sync1 = new PeriodicSync(account1, authority1, extras1, period1, flex1);
+ PeriodicSync sync2 = new PeriodicSync(account1, authority1, extras2, period1, flex1);
+ PeriodicSync sync3 = new PeriodicSync(account1, authority2, extras1, period1, flex1);
+ PeriodicSync sync4 = new PeriodicSync(account1, authority2, extras2, period2, flex2);
+ PeriodicSync sync5 = new PeriodicSync(account2, authority1, extras1, period1, flex1);
MockContentResolver mockResolver = new MockContentResolver();
@@ -185,11 +283,11 @@
engine.setIsSyncable(account2, 0, authority2, 0);
engine.setSyncAutomatically(account2, 0, authority2, true);
- engine.addPeriodicSync(sync1.account, 0, sync1.authority, sync1.extras, sync1.period);
- engine.addPeriodicSync(sync2.account, 0, sync2.authority, sync2.extras, sync2.period);
- engine.addPeriodicSync(sync3.account, 0, sync3.authority, sync3.extras, sync3.period);
- engine.addPeriodicSync(sync4.account, 0, sync4.authority, sync4.extras, sync4.period);
- engine.addPeriodicSync(sync5.account, 0, sync5.authority, sync5.extras, sync5.period);
+ engine.addPeriodicSync(sync1, 0);
+ engine.addPeriodicSync(sync2, 0);
+ engine.addPeriodicSync(sync3, 0);
+ engine.addPeriodicSync(sync4, 0);
+ engine.addPeriodicSync(sync5, 0);
engine.writeAllState();
engine.clearAndReadState();
@@ -220,6 +318,131 @@
}
@MediumTest
+ /**
+ * V2 introduces flex time as well as service components.
+ * @throws Exception
+ */
+ public void testAuthorityParsingV2() throws Exception {
+ final Account account = new Account("account1", "type1");
+ final String authority1 = "auth1";
+ final String authority2 = "auth2";
+ final String authority3 = "auth3";
+
+ final long dayPoll = (60 * 60 * 24);
+ final long dayFuzz = 60;
+ final long thousandSecs = 1000;
+ final long thousandSecsFuzz = 100;
+ final Bundle extras = new Bundle();
+ PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, dayPoll, dayFuzz);
+ PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, dayPoll, dayFuzz);
+ PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, dayPoll, dayFuzz);
+ PeriodicSync sync1s = new PeriodicSync(account, authority1, extras, thousandSecs, thousandSecsFuzz);
+ PeriodicSync sync2s = new PeriodicSync(account, authority2, extras, thousandSecs, thousandSecsFuzz);
+ PeriodicSync sync3s = new PeriodicSync(account, authority3, extras, thousandSecs, thousandSecsFuzz);
+ MockContentResolver mockResolver = new MockContentResolver();
+
+ final TestContext testContext = new TestContext(mockResolver, getContext());
+
+ byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<accounts version=\"2\" >\n"
+ + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" >"
+ + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+ + "\n</authority>"
+ + "<authority id=\"1\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth2\" >"
+ + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+ + "\n</authority>"
+ // No user defaults to user 0 - all users.
+ + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" >"
+ + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+ + "\n</authority>"
+ + "<authority id=\"3\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth3\" >"
+ + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+ + "\n</authority>"
+ + "</accounts>").getBytes();
+
+ File syncDir = getSyncDir();
+ syncDir.mkdirs();
+ AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+ FileOutputStream fos = accountInfoFile.startWrite();
+ fos.write(accountsFileData);
+ accountInfoFile.finishWrite(fos);
+
+ SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
+
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ assertEquals("Got incorrect # of syncs", 1, syncs.size());
+ assertEquals(sync1, syncs.get(0));
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ assertEquals(1, syncs.size());
+ assertEquals(sync2, syncs.get(0));
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ assertEquals(1, syncs.size());
+ assertEquals(sync3, syncs.get(0));
+
+ syncs = engine.getPeriodicSyncs(account, 1, authority3);
+ assertEquals(1, syncs.size());
+ assertEquals(sync3, syncs.get(0));
+
+ // Test empty periodic data.
+ accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<accounts version=\"2\">\n"
+ + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n"
+ + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\" />\n"
+ + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\" />\n"
+ + "</accounts>\n").getBytes();
+
+ accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+ fos = accountInfoFile.startWrite();
+ fos.write(accountsFileData);
+ accountInfoFile.finishWrite(fos);
+
+ engine.clearAndReadState();
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ assertEquals(0, syncs.size());
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ assertEquals(0, syncs.size());
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ assertEquals(0, syncs.size());
+
+ accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<accounts version=\"2\">\n"
+ + "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n"
+ + "<periodicSync period=\"1000\" />\n"
+ + "</authority>"
+ + "<authority id=\"1\" account=\"account1\" type=\"type1\" authority=\"auth2\">\n"
+ + "<periodicSync period=\"1000\" />\n"
+ + "</authority>"
+ + "<authority id=\"2\" account=\"account1\" type=\"type1\" authority=\"auth3\">\n"
+ + "<periodicSync period=\"1000\" />\n"
+ + "</authority>"
+ + "</accounts>\n").getBytes();
+
+ accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+ fos = accountInfoFile.startWrite();
+ fos.write(accountsFileData);
+ accountInfoFile.finishWrite(fos);
+
+ engine.clearAndReadState();
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ assertEquals(1, syncs.size());
+ assertEquals(sync1s, syncs.get(0));
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ assertEquals(1, syncs.size());
+ assertEquals(sync2s, syncs.get(0));
+
+ syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ assertEquals(1, syncs.size());
+ assertEquals(sync3s, syncs.get(0));
+ }
+
+ @MediumTest
public void testAuthorityParsing() throws Exception {
final Account account = new Account("account1", "type1");
final String authority1 = "auth1";
@@ -256,7 +479,7 @@
List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
assertEquals(1, syncs.size());
- assertEquals(sync1, syncs.get(0));
+ assertEquals("expected sync1: " + sync1.toString() + " == sync 2" + syncs.get(0).toString(), sync1, syncs.get(0));
syncs = engine.getPeriodicSyncs(account, 0, authority2);
assertEquals(1, syncs.size());
@@ -451,6 +674,11 @@
}
@Override
+ public Resources getResources() {
+ return mRealContext.getResources();
+ }
+
+ @Override
public File getFilesDir() {
return mRealContext.getFilesDir();
}