Merge "Ensure Binder finalizer handles partially initialized instances."
diff --git a/api/current.xml b/api/current.xml
index 868f6fc..047c25c 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -195481,7 +195481,7 @@
</parameter>
<parameter name="encoding" type="java.lang.String">
</parameter>
-<parameter name="failUrl" type="java.lang.String">
+<parameter name="historyUrl" type="java.lang.String">
</parameter>
</method>
<method name="loadUrl"
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 6658842..55bb581 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -370,7 +370,9 @@
const char *kMimeTypes[] = {
MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
- MEDIA_MIMETYPE_VIDEO_H263
+ MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
+ MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
+ MEDIA_MIMETYPE_AUDIO_MPEG
};
for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e8ab51fd..b3223e5 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.IPackageDataObserver;
import android.graphics.Bitmap;
@@ -859,6 +860,22 @@
}
/**
+ * Returns a list of application processes installed on external media
+ * that are running on the device.
+ *
+ * @return Returns a list of ApplicationInfo records, or null if none
+ * This list ordering is not specified.
+ * @hide
+ */
+ public List<ApplicationInfo> getRunningExternalApplications() {
+ try {
+ return ActivityManagerNative.getDefault().getRunningExternalApplications();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Returns a list of application processes that are running on the device.
*
* @return Returns a list of RunningAppProcessInfo records, or null if there are no
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index adadfeb..f694285 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -491,6 +491,14 @@
return true;
}
+ case GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ List<ApplicationInfo> list = getRunningExternalApplications();
+ reply.writeNoException();
+ reply.writeTypedList(list);
+ return true;
+ }
+
case MOVE_TASK_TO_FRONT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int task = data.readInt();
@@ -1716,6 +1724,19 @@
reply.recycle();
return list;
}
+ public List<ApplicationInfo> getRunningExternalApplications()
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ ArrayList<ApplicationInfo> list
+ = reply.createTypedArrayList(ApplicationInfo.CREATOR);
+ data.recycle();
+ reply.recycle();
+ return list;
+ }
public void moveTaskToFront(int task) throws RemoteException
{
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ea0e952..31f0a63 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -262,9 +262,13 @@
* SIGUSR1 is delivered. All others are ignored.
*/
public void signalPersistentProcesses(int signal) throws RemoteException;
- // Retrieve running application processes in the system
+ // Retrieve info of applications installed on external media that are currently
+ // running.
public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
throws RemoteException;
+ // Retrieve running application processes in the system
+ public List<ApplicationInfo> getRunningExternalApplications()
+ throws RemoteException;
// Get device configuration
public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException;
@@ -508,4 +512,5 @@
int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104;
int WILL_ACTIVITY_BE_VISIBLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+105;
int START_ACTIVITY_WITH_CONFIG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+106;
+ int GET_RUNNING_EXTERNAL_APPLICATIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+107;
}
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index df48f04..5c8ee18 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -215,7 +215,9 @@
// the accounts are not set yet
sendCheckAlarmsMessage();
- mSyncStorageEngine.doDatabaseCleanup(accounts);
+ if (mBootCompleted) {
+ mSyncStorageEngine.doDatabaseCleanup(accounts);
+ }
if (accounts.length > 0) {
// If this is the first time this was called after a bootup then
@@ -1317,6 +1319,7 @@
private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
public void onBootCompleted() {
mBootCompleted = true;
+ mSyncStorageEngine.doDatabaseCleanup(AccountManager.get(mContext).getAccounts());
if (mReadyToRunLatch != null) {
mReadyToRunLatch.countDown();
}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index 03e606f..daad95c 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -122,7 +122,15 @@
private static final boolean SYNC_ENABLED_DEFAULT = false;
// the version of the accounts xml file format
- private static final int ACCOUNTS_VERSION = 1;
+ private static final int ACCOUNTS_VERSION = 2;
+
+ private static HashMap<String, String> sAuthorityRenames;
+
+ static {
+ sAuthorityRenames = new HashMap<String, String>();
+ sAuthorityRenames.put("contacts", "com.android.contacts");
+ sAuthorityRenames.put("calendar", "com.android.calendar");
+ }
public static class PendingOperation {
final Account account;
@@ -1281,7 +1289,9 @@
private void removeAuthorityLocked(Account account, String authorityName) {
AccountInfo accountInfo = mAccounts.get(account);
if (accountInfo != null) {
- if (accountInfo.authorities.remove(authorityName) != null) {
+ final AuthorityInfo authorityInfo = accountInfo.authorities.remove(authorityName);
+ if (authorityInfo != null) {
+ mAuthorities.remove(authorityInfo.ident);
writeAccountInfoLocked();
}
}
@@ -1407,11 +1417,61 @@
}
}
+ if (maybeMigrateSettingsForRenamedAuthorities()) {
+ writeNeeded = true;
+ }
+
if (writeNeeded) {
writeAccountInfoLocked();
}
}
+ /**
+ * some authority names have changed. copy over their settings and delete the old ones
+ * @return true if a change was made
+ */
+ private boolean maybeMigrateSettingsForRenamedAuthorities() {
+ boolean writeNeeded = false;
+
+ ArrayList<AuthorityInfo> authoritiesToRemove = new ArrayList<AuthorityInfo>();
+ final int N = mAuthorities.size();
+ for (int i=0; i<N; i++) {
+ AuthorityInfo authority = mAuthorities.valueAt(i);
+ // skip this authority if it isn't one of the renamed ones
+ final String newAuthorityName = sAuthorityRenames.get(authority.authority);
+ if (newAuthorityName == null) {
+ continue;
+ }
+
+ // remember this authority so we can remove it later. we can't remove it
+ // now without messing up this loop iteration
+ authoritiesToRemove.add(authority);
+
+ // this authority isn't enabled, no need to copy it to the new authority name since
+ // the default is "disabled"
+ if (!authority.enabled) {
+ continue;
+ }
+
+ // if we already have a record of this new authority then don't copy over the settings
+ if (getAuthorityLocked(authority.account, newAuthorityName, "cleanup") != null) {
+ continue;
+ }
+
+ AuthorityInfo newAuthority = getOrCreateAuthorityLocked(authority.account,
+ newAuthorityName, -1 /* ident */, false /* doWrite */);
+ newAuthority.enabled = true;
+ writeNeeded = true;
+ }
+
+ for (AuthorityInfo authorityInfo : authoritiesToRemove) {
+ removeAuthorityLocked(authorityInfo.account, authorityInfo.authority);
+ writeNeeded = true;
+ }
+
+ return writeNeeded;
+ }
+
private AuthorityInfo parseAuthority(XmlPullParser parser, int version) {
AuthorityInfo authority = null;
int id = -1;
@@ -1424,14 +1484,15 @@
Log.e(TAG, "the id of the authority is null", e);
}
if (id >= 0) {
+ String authorityName = parser.getAttributeValue(null, "authority");
+ String enabled = parser.getAttributeValue(null, "enabled");
+ String syncable = parser.getAttributeValue(null, "syncable");
String accountName = parser.getAttributeValue(null, "account");
String accountType = parser.getAttributeValue(null, "type");
if (accountType == null) {
accountType = "com.google";
+ syncable = "unknown";
}
- String authorityName = parser.getAttributeValue(null, "authority");
- String enabled = parser.getAttributeValue(null, "enabled");
- String syncable = parser.getAttributeValue(null, "syncable");
authority = mAuthorities.get(id);
if (DEBUG_FILE) Log.v(TAG, "Adding authority: account="
+ accountName + " auth=" + authorityName
@@ -1456,7 +1517,7 @@
authority.syncable = -1;
} else {
authority.syncable =
- (syncable == null || Boolean.parseBoolean(enabled)) ? 1 : 0;
+ (syncable == null || Boolean.parseBoolean(syncable)) ? 1 : 0;
}
} else {
Log.w(TAG, "Failure adding authority: account="
@@ -1546,13 +1607,11 @@
out.attribute(null, "account", authority.account.name);
out.attribute(null, "type", authority.account.type);
out.attribute(null, "authority", authority.authority);
- if (!authority.enabled) {
- out.attribute(null, "enabled", "false");
- }
+ out.attribute(null, "enabled", Boolean.toString(authority.enabled));
if (authority.syncable < 0) {
out.attribute(null, "syncable", "unknown");
- } else if (authority.syncable == 0) {
- out.attribute(null, "syncable", "false");
+ } else {
+ out.attribute(null, "syncable", Boolean.toString(authority.syncable != 0));
}
for (Pair<Bundle, Long> periodicSync : authority.periodicSyncs) {
out.startTag(null, "periodicSync");
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index e6f9bed..3b7416e 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -213,16 +213,23 @@
// Things related to query logging/sampling for debugging
// slow/frequent queries during development. Always log queries
- // which take 500ms+; shorter queries are sampled accordingly.
- // Commit statements, which are typically slow, are logged
- // together with the most recently executed SQL statement, for
- // disambiguation.
- private static final int QUERY_LOG_TIME_IN_MILLIS = 500;
+ // which take (by default) 500ms+; shorter queries are sampled
+ // accordingly. Commit statements, which are typically slow, are
+ // logged together with the most recently executed SQL statement,
+ // for disambiguation. The 500ms value is configurable via a
+ // SystemProperty, but developers actively debugging database I/O
+ // should probably use the regular log tunable,
+ // LOG_SLOW_QUERIES_PROPERTY, defined below.
+ private static int sQueryLogTimeInMillis = 0; // lazily initialized
private static final int QUERY_LOG_SQL_LENGTH = 64;
private static final String COMMIT_SQL = "COMMIT;";
private final Random mRandom = new Random();
private String mLastSqlStatement = null;
+ // String prefix for slow database query EventLog records that show
+ // lock acquistions of the database.
+ /* package */ static final String GET_LOCK_LOG_PREFIX = "GETLOCK:";
+
/** Used by native code, do not rename */
/* package */ int mNativeHandle = 0;
@@ -340,15 +347,18 @@
private boolean mLockingEnabled = true;
/* package */ void onCorruption() {
+ Log.e(TAG, "Removing corrupt database: " + mPath);
+ EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
try {
// Close the database (if we can), which will cause subsequent operations to fail.
close();
} finally {
- Log.e(TAG, "Removing corrupt database: " + mPath);
- EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
// Delete the corrupt file. Don't re-create it now -- that would just confuse people
// -- but the next time someone tries to open it, they can set it up from scratch.
- new File(mPath).delete();
+ if (!mPath.equalsIgnoreCase(":memory")) {
+ // delete is only for non-memory database files
+ new File(mPath).delete();
+ }
}
}
@@ -490,6 +500,9 @@
* {@link #yieldIfContendedSafely}.
*/
public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
lockForced();
boolean ok = false;
try {
@@ -535,6 +548,9 @@
* are committed and rolled back.
*/
public void endTransaction() {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
if (!mLock.isHeldByCurrentThread()) {
throw new IllegalStateException("no transaction pending");
}
@@ -595,6 +611,9 @@
* transaction is already marked as successful.
*/
public void setTransactionSuccessful() {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
if (!mLock.isHeldByCurrentThread()) {
throw new IllegalStateException("no transaction pending");
}
@@ -807,7 +826,10 @@
// TODO: should we do this for other open failures?
Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
EventLog.writeEvent(EVENT_DB_CORRUPT, path);
- new File(path).delete();
+ if (!path.equalsIgnoreCase(":memory")) {
+ // delete is only for non-memory database files
+ new File(path).delete();
+ }
sqliteDatabase = new SQLiteDatabase(path, factory, flags);
}
ActiveDatabases.getInstance().mActiveDatabases.add(
@@ -849,14 +871,14 @@
* Close the database.
*/
public void close() {
+ if (!isOpen()) {
+ return; // already closed
+ }
lock();
try {
closeClosable();
// close this database instance - regardless of its reference count value
onAllReferencesReleased();
- // set path to null, to cause bad stuff to happen if this object is reused without
- // being opened first
- mPath = null;
} finally {
unlock();
}
@@ -893,6 +915,9 @@
* @return the database version
*/
public int getVersion() {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
SQLiteStatement prog = null;
lock();
try {
@@ -911,6 +936,9 @@
* @param version the new database version
*/
public void setVersion(int version) {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
execSQL("PRAGMA user_version = " + version);
}
@@ -920,6 +948,9 @@
* @return the new maximum database size
*/
public long getMaximumSize() {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
SQLiteStatement prog = null;
lock();
try {
@@ -941,6 +972,9 @@
* @return the new maximum database size
*/
public long setMaximumSize(long numBytes) {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
SQLiteStatement prog = null;
lock();
try {
@@ -966,6 +1000,9 @@
* @return the database page size, in bytes
*/
public long getPageSize() {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
SQLiteStatement prog = null;
lock();
try {
@@ -987,6 +1024,9 @@
* @param numBytes the database page size, in bytes
*/
public void setPageSize(long numBytes) {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
execSQL("PRAGMA page_size = " + numBytes);
}
@@ -1103,6 +1143,9 @@
* @return a pre-compiled statement object.
*/
public SQLiteStatement compileStatement(String sql) throws SQLException {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
lock();
try {
return new SQLiteStatement(this, sql);
@@ -1183,6 +1226,9 @@
boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit) {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
@@ -1289,6 +1335,9 @@
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable) {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
long timeStart = 0;
if (Config.LOGV || mSlowQueryThreshold != -1) {
@@ -1298,19 +1347,19 @@
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
Cursor cursor = null;
+ int count = 0;
try {
cursor = driver.query(
cursorFactory != null ? cursorFactory : mFactory,
selectionArgs);
+
+ // Force query execution
+ if (cursor != null) {
+ count = cursor.getCount();
+ }
} finally {
if (Config.LOGV || mSlowQueryThreshold != -1) {
- // Force query execution
- if (cursor != null) {
- cursor.moveToFirst();
- cursor.moveToPosition(-1);
- }
-
long duration = System.currentTimeMillis() - timeStart;
if (Config.LOGV || duration >= mSlowQueryThreshold) {
@@ -1318,7 +1367,7 @@
"query (" + duration + " ms): " + driver.toString() + ", args are "
+ (selectionArgs != null
? TextUtils.join(",", selectionArgs)
- : "<null>"));
+ : "<null>") + ", count is " + count);
}
}
}
@@ -1675,8 +1724,12 @@
* @throws SQLException If the SQL string is invalid for some reason
*/
public void execSQL(String sql) throws SQLException {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
long timeStart = SystemClock.uptimeMillis();
lock();
+ logTimeStat(mLastSqlStatement, timeStart, GET_LOCK_LOG_PREFIX);
try {
native_execSQL(sql);
} catch (SQLiteDatabaseCorruptException e) {
@@ -1690,9 +1743,9 @@
// SQL statement for disambiguation. Note that instance
// equality to COMMIT_SQL is safe here.
if (sql == COMMIT_SQL) {
- logTimeStat(sql + mLastSqlStatement, timeStart);
+ logTimeStat(mLastSqlStatement, timeStart, COMMIT_SQL);
} else {
- logTimeStat(sql, timeStart);
+ logTimeStat(sql, timeStart, null);
}
}
@@ -1706,6 +1759,9 @@
* @throws SQLException If the SQL string is invalid for some reason
*/
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
+ if (!isOpen()) {
+ throw new IllegalStateException("database not open");
+ }
if (bindArgs == null) {
throw new IllegalArgumentException("Empty bindArgs");
}
@@ -1809,9 +1865,11 @@
return mPath;
}
-
-
/* package */ void logTimeStat(String sql, long beginMillis) {
+ logTimeStat(sql, beginMillis, null);
+ }
+
+ /* package */ void logTimeStat(String sql, long beginMillis, String prefix) {
// Keep track of the last statement executed here, as this is
// the common funnel through which all methods of hitting
// libsqlite eventually flow.
@@ -1823,13 +1881,27 @@
int samplePercent;
long durationMillis = SystemClock.uptimeMillis() - beginMillis;
- if (durationMillis >= QUERY_LOG_TIME_IN_MILLIS) {
+ if (durationMillis == 0 && prefix == GET_LOCK_LOG_PREFIX) {
+ // The common case is locks being uncontended. Don't log those,
+ // even at 1%, which is our default below.
+ return;
+ }
+ if (sQueryLogTimeInMillis == 0) {
+ sQueryLogTimeInMillis = SystemProperties.getInt("db.db_operation.threshold_ms", 500);
+ }
+ if (durationMillis >= sQueryLogTimeInMillis) {
samplePercent = 100;
- } else {
- samplePercent = (int) (100 * durationMillis / QUERY_LOG_TIME_IN_MILLIS) + 1;
+ } else {;
+ samplePercent = (int) (100 * durationMillis / sQueryLogTimeInMillis) + 1;
if (mRandom.nextInt(100) >= samplePercent) return;
}
+ // Note: the prefix will be "COMMIT;" or "GETLOCK:" when non-null. We wait to do
+ // it here so we avoid allocating in the common case.
+ if (prefix != null) {
+ sql = prefix + sql;
+ }
+
if (sql.length() > QUERY_LOG_SQL_LENGTH) sql = sql.substring(0, QUERY_LOG_SQL_LENGTH);
// ActivityThread.currentPackageName() only returns non-null if the
@@ -2059,6 +2131,10 @@
static ActiveDatabases getInstance() {return activeDatabases;}
}
+ /**
+ * this method is used to collect data about ALL open databases in the current process.
+ * bugreport is a user of this data.
+ */
/* package */ static ArrayList<DbStats> getDbStats() {
ArrayList<DbStats> dbStatsList = new ArrayList<DbStats>();
for (WeakReference<SQLiteDatabase> w : ActiveDatabases.getInstance().mActiveDatabases) {
@@ -2076,6 +2152,9 @@
// get list of attached dbs and for each db, get its size and pagesize
ArrayList<Pair<String, String>> attachedDbs = getAttachedDbs(db);
+ if (attachedDbs == null) {
+ continue;
+ }
for (int i = 0; i < attachedDbs.size(); i++) {
Pair<String, String> p = attachedDbs.get(i);
long pageCount = getPragmaVal(db, p.first + ".page_count;");
@@ -2095,7 +2174,10 @@
dbName += " : " + p.second.substring((idx != -1) ? ++idx : 0);
}
}
- dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(), lookasideUsed));
+ if (pageCount > 0) {
+ dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
+ lookasideUsed));
+ }
}
}
return dbStatsList;
@@ -2108,6 +2190,9 @@
* TODO: use this to do all pragma's in this class
*/
private static long getPragmaVal(SQLiteDatabase db, String pragma) {
+ if (!db.isOpen()) {
+ return 0;
+ }
SQLiteStatement prog = null;
try {
prog = new SQLiteStatement(db, "PRAGMA " + pragma);
@@ -2124,6 +2209,9 @@
* TODO: move this to {@link DatabaseUtils}
*/
private static ArrayList<Pair<String, String>> getAttachedDbs(SQLiteDatabase dbObj) {
+ if (!dbObj.isOpen()) {
+ return null;
+ }
ArrayList<Pair<String, String>> attachedDbs = new ArrayList<Pair<String, String>>();
Cursor c = dbObj.rawQuery("pragma database_list;", null);
while (c.moveToNext()) {
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 7cd9561..43d2fac 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -51,20 +51,20 @@
/**
* Reads rows into a buffer. This method acquires the database lock.
- *
+ *
* @param window The window to fill into
* @return number of total rows in the query
*/
- /* package */ int fillWindow(CursorWindow window,
+ /* package */ int fillWindow(CursorWindow window,
int maxRead, int lastPos) {
long timeStart = SystemClock.uptimeMillis();
mDatabase.lock();
-
+ mDatabase.logTimeStat(mSql, timeStart, SQLiteDatabase.GET_LOCK_LOG_PREFIX);
try {
acquireReference();
try {
window.acquireReference();
- // if the start pos is not equal to 0, then most likely window is
+ // if the start pos is not equal to 0, then most likely window is
// too small for the data set, loading by another thread
// is not safe in this situation. the native code will ignore maxRead
int numRows = native_fill_window(window, window.getStartPosition(), mOffsetIndex,
@@ -83,7 +83,7 @@
mDatabase.onCorruption();
throw e;
} finally {
- window.releaseReference();
+ window.releaseReference();
}
} finally {
releaseReference();
diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java
index b0923d1..09f6f4f 100644
--- a/core/java/android/net/http/Headers.java
+++ b/core/java/android/net/http/Headers.java
@@ -72,6 +72,7 @@
public final static String SET_COOKIE = "set-cookie";
public final static String PRAGMA = "pragma";
public final static String REFRESH = "refresh";
+ public final static String X_PERMITTED_CROSS_DOMAIN_POLICIES = "x-permitted-cross-domain-policies";
// following hash are generated by String.hashCode()
private final static int HASH_TRANSFER_ENCODING = 1274458357;
@@ -92,6 +93,7 @@
private final static int HASH_SET_COOKIE = 1237214767;
private final static int HASH_PRAGMA = -980228804;
private final static int HASH_REFRESH = 1085444827;
+ private final static int HASH_X_PERMITTED_CROSS_DOMAIN_POLICIES = -1345594014;
// keep any headers that require direct access in a presized
// string array
@@ -113,8 +115,9 @@
private final static int IDX_SET_COOKIE = 15;
private final static int IDX_PRAGMA = 16;
private final static int IDX_REFRESH = 17;
+ private final static int IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES = 18;
- private final static int HEADER_COUNT = 18;
+ private final static int HEADER_COUNT = 19;
/* parsed values */
private long transferEncoding;
@@ -141,7 +144,8 @@
ETAG,
SET_COOKIE,
PRAGMA,
- REFRESH
+ REFRESH,
+ X_PERMITTED_CROSS_DOMAIN_POLICIES
};
// Catch-all for headers not explicitly handled
@@ -287,6 +291,11 @@
mHeaders[IDX_REFRESH] = val;
}
break;
+ case HASH_X_PERMITTED_CROSS_DOMAIN_POLICIES:
+ if (name.equals(X_PERMITTED_CROSS_DOMAIN_POLICIES)) {
+ mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES] = val;
+ }
+ break;
default:
mExtraHeaderNames.add(name);
mExtraHeaderValues.add(val);
@@ -361,6 +370,10 @@
return mHeaders[IDX_REFRESH];
}
+ public String getXPermittedCrossDomainPolicies() {
+ return mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES];
+ }
+
public void setContentLength(long value) {
this.contentLength = value;
}
@@ -409,6 +422,10 @@
mHeaders[IDX_ETAG] = value;
}
+ public void setXPermittedCrossDomainPolicies(String value) {
+ mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES] = value;
+ }
+
public interface HeaderCallback {
public void header(String name, String value);
}
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 1a3a289..103fd94 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -200,7 +200,7 @@
if (mBodyProvider != null) mBodyProvider.reset();
} catch (java.io.IOException ex) {
if (HttpLog.LOGV) {
- HttpLog.v("setupAuthResponse() failed to reset body provider");
+ HttpLog.v("setupRedirect() failed to reset body provider");
}
return false;
}
@@ -443,6 +443,16 @@
* Creates and queues new request.
*/
private void createAndQueueNewRequest() {
+ // mConnection is non-null if and only if the requests are synchronous.
+ if (mConnection != null) {
+ RequestHandle newHandle = mRequestQueue.queueSynchronousRequest(
+ mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
+ mBodyProvider, mBodyLength);
+ mRequest = newHandle.mRequest;
+ mConnection = newHandle.mConnection;
+ newHandle.processRequest();
+ return;
+ }
mRequest = mRequestQueue.queueRequest(
mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
mBodyProvider,
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index 9742b05..a81e16b 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -273,7 +273,8 @@
* @hide
*/
public ParcelFileDescriptor getParcelFileDescriptor() throws IOException {
- return new ParcelFileDescriptor(getFileDescriptor());
+ FileDescriptor fd = getFileDescriptor();
+ return fd != null ? new ParcelFileDescriptor(fd) : null;
}
/**
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 3fcb18e..0a3b2cf 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -113,7 +113,7 @@
}
FileDescriptor fd = Parcel.openFileDescriptor(path, mode);
- return new ParcelFileDescriptor(fd);
+ return fd != null ? new ParcelFileDescriptor(fd) : null;
}
/**
@@ -127,7 +127,7 @@
*/
public static ParcelFileDescriptor fromSocket(Socket socket) {
FileDescriptor fd = getFileDescriptorFromSocket(socket);
- return new ParcelFileDescriptor(fd);
+ return fd != null ? new ParcelFileDescriptor(fd) : null;
}
// Extracts the file descriptor from the specified socket and returns it untouched
@@ -163,7 +163,10 @@
* If an error occurs attempting to close this ParcelFileDescriptor.
*/
public void close() throws IOException {
- mClosed = true;
+ synchronized (this) {
+ if (mClosed) return;
+ mClosed = true;
+ }
if (mParcelDescriptor != null) {
// If this is a proxy to another file descriptor, just call through to its
// close method.
@@ -235,6 +238,9 @@
/*package */ParcelFileDescriptor(FileDescriptor descriptor) {
super();
+ if (descriptor == null) {
+ throw new NullPointerException("descriptor must not be null");
+ }
mFileDescriptor = descriptor;
mParcelDescriptor = null;
}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 27092ae..a1ad1ee 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -276,71 +276,47 @@
public static final void updateVisitedHistory(ContentResolver cr,
String url, boolean real) {
long now = new Date().getTime();
- new UpdateVisitedHistory(cr, url, real, now).execute();
- }
-
- /**
- * Runnable to perform the update in a separate thread.
- */
- private static class UpdateVisitedHistory extends AsyncTask<Void, Void, Void> {
- private final ContentResolver mContentResolver;
- private final String mUrl;
- private final boolean mReal;
- private final long mNow;
-
- public UpdateVisitedHistory(ContentResolver cr, String url,
- boolean real, long now) {
- mContentResolver = cr;
- mUrl = url;
- mReal = real;
- mNow = now;
- }
-
- protected Void doInBackground(Void... unused) {
- Cursor c = null;
- try {
- c = getVisitedLike(mContentResolver, mUrl);
- /* We should only get one answer that is exactly the same. */
- if (c.moveToFirst()) {
- ContentValues map = new ContentValues();
- if (mReal) {
- map.put(BookmarkColumns.VISITS, c
- .getInt(HISTORY_PROJECTION_VISITS_INDEX) + 1);
- } else {
- map.put(BookmarkColumns.USER_ENTERED, 1);
- }
- map.put(BookmarkColumns.DATE, mNow);
- String[] projection = new String[]
- { Integer.valueOf(c.getInt(0)).toString() };
- mContentResolver.update(BOOKMARKS_URI, map, "_id = ?",
- projection);
+ Cursor c = null;
+ try {
+ c = getVisitedLike(cr, url);
+ /* We should only get one answer that is exactly the same. */
+ if (c.moveToFirst()) {
+ ContentValues map = new ContentValues();
+ if (real) {
+ map.put(BookmarkColumns.VISITS, c
+ .getInt(HISTORY_PROJECTION_VISITS_INDEX) + 1);
} else {
- truncateHistory(mContentResolver);
- ContentValues map = new ContentValues();
- int visits;
- int user_entered;
- if (mReal) {
- visits = 1;
- user_entered = 0;
- } else {
- visits = 0;
- user_entered = 1;
- }
- map.put(BookmarkColumns.URL, mUrl);
- map.put(BookmarkColumns.VISITS, visits);
- map.put(BookmarkColumns.DATE, mNow);
- map.put(BookmarkColumns.BOOKMARK, 0);
- map.put(BookmarkColumns.TITLE, mUrl);
- map.put(BookmarkColumns.CREATED, 0);
- map.put(BookmarkColumns.USER_ENTERED, user_entered);
- mContentResolver.insert(BOOKMARKS_URI, map);
+ map.put(BookmarkColumns.USER_ENTERED, 1);
}
- } catch (IllegalStateException e) {
- Log.e(LOGTAG, "updateVisitedHistory", e);
- } finally {
- if (c != null) c.close();
+ map.put(BookmarkColumns.DATE, now);
+ String[] projection = new String[]
+ { Integer.valueOf(c.getInt(0)).toString() };
+ cr.update(BOOKMARKS_URI, map, "_id = ?", projection);
+ } else {
+ truncateHistory(cr);
+ ContentValues map = new ContentValues();
+ int visits;
+ int user_entered;
+ if (real) {
+ visits = 1;
+ user_entered = 0;
+ } else {
+ visits = 0;
+ user_entered = 1;
+ }
+ map.put(BookmarkColumns.URL, url);
+ map.put(BookmarkColumns.VISITS, visits);
+ map.put(BookmarkColumns.DATE, now);
+ map.put(BookmarkColumns.BOOKMARK, 0);
+ map.put(BookmarkColumns.TITLE, url);
+ map.put(BookmarkColumns.CREATED, 0);
+ map.put(BookmarkColumns.USER_ENTERED, user_entered);
+ cr.insert(BOOKMARKS_URI, map);
}
- return null;
+ } catch (IllegalStateException e) {
+ Log.e(LOGTAG, "updateVisitedHistory", e);
+ } finally {
+ if (c != null) c.close();
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2ba38c23..fc207ac 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2903,6 +2903,12 @@
public static final String DROPBOX_AGE_SECONDS =
"dropbox_age_seconds";
/**
+ * Maximum number of entry files which {@link android.os.IDropBox} will keep around.
+ * @hide
+ */
+ public static final String DROPBOX_MAX_FILES =
+ "dropbox_max_files";
+ /**
* Maximum amount of disk space used by {@link android.os.IDropBox} no matter what.
* @hide
*/
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 344b390..7e871d0 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -17,7 +17,10 @@
package android.webkit;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -31,7 +34,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.Surface;
-import android.view.WindowOrientationListener;
+import android.view.WindowManager;
import junit.framework.Assert;
@@ -73,8 +76,10 @@
// Attached Javascript interfaces
private Map<String, Object> mJSInterfaceMap;
+ // WindowManager to obtain the Display configuration.
+ private WindowManager mWindowManager;
// Orientation listener
- private WindowOrientationListener mOrientationListener;
+ private BroadcastReceiver mOrientationListener;
// message ids
// a message posted when a frame loading is completed
@@ -153,9 +158,15 @@
Log.v(LOGTAG, "BrowserFrame constructor: this=" + this);
}
- mOrientationListener = new WindowOrientationListener(context) {
- @Override
- public void onOrientationChanged(int orientation) {
+ mWindowManager = (WindowManager) context.getSystemService(
+ Context.WINDOW_SERVICE);
+ mOrientationListener = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_CONFIGURATION_CHANGED.equals(
+ intent.getAction())) {
+ int orientation =
+ mWindowManager.getDefaultDisplay().getOrientation();
switch (orientation) {
case Surface.ROTATION_90:
orientation = 90;
@@ -174,9 +185,12 @@
}
sendMessage(
obtainMessage(ORIENTATION_CHANGED, orientation, 0));
+
}
+ }
};
- mOrientationListener.enable();
+ context.registerReceiver(mOrientationListener,
+ new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
}
/**
@@ -213,21 +227,19 @@
/**
* Load the content as if it was loaded by the provided base URL. The
- * failUrl is used as the history entry for the load data. If null or
- * an empty string is passed for the failUrl, then no history entry is
- * created.
+ * historyUrl is used as the history entry for the load data.
*
* @param baseUrl Base URL used to resolve relative paths in the content
* @param data Content to render in the browser
* @param mimeType Mimetype of the data being passed in
* @param encoding Character set encoding of the provided data.
- * @param failUrl URL to use if the content fails to load or null.
+ * @param historyUrl URL to use as the history entry.
*/
public void loadData(String baseUrl, String data, String mimeType,
- String encoding, String failUrl) {
+ String encoding, String historyUrl) {
mLoadInitFromJava = true;
- if (failUrl == null) {
- failUrl = "";
+ if (historyUrl == null || historyUrl.length() == 0) {
+ historyUrl = "about:blank";
}
if (data == null) {
data = "";
@@ -241,7 +253,7 @@
if (mimeType == null || mimeType.length() == 0) {
mimeType = "text/html";
}
- nativeLoadData(baseUrl, data, mimeType, encoding, failUrl);
+ nativeLoadData(baseUrl, data, mimeType, encoding, historyUrl);
mLoadInitFromJava = false;
}
@@ -385,7 +397,7 @@
* Destroy all native components of the BrowserFrame.
*/
public void destroy() {
- mOrientationListener.disable();
+ mContext.unregisterReceiver(mOrientationListener);
nativeDestroyFrame();
mBlockMessages = true;
removeCallbacksAndMessages(null);
@@ -594,7 +606,9 @@
int cacheMode,
boolean mainResource,
boolean userGesture,
- boolean synchronous) {
+ boolean synchronous,
+ String username,
+ String password) {
PerfChecker checker = new PerfChecker();
if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
@@ -667,7 +681,7 @@
// Create a LoadListener
LoadListener loadListener = LoadListener.getLoadListener(mContext,
this, url, loaderHandle, synchronous, isMainFramePage,
- mainResource, userGesture, postDataIdentifier);
+ mainResource, userGesture, postDataIdentifier, username, password);
mCallbackProxy.onLoadResource(url);
@@ -916,7 +930,7 @@
private native void nativePostUrl(String url, byte[] postData);
private native void nativeLoadData(String baseUrl, String data,
- String mimeType, String encoding, String failUrl);
+ String mimeType, String encoding, String historyUrl);
/**
* Stop loading the current page.
diff --git a/core/java/android/webkit/CacheLoader.java b/core/java/android/webkit/CacheLoader.java
index aeb537c..05c02b0 100644
--- a/core/java/android/webkit/CacheLoader.java
+++ b/core/java/android/webkit/CacheLoader.java
@@ -67,5 +67,9 @@
if (!TextUtils.isEmpty(mCacheResult.contentdisposition)) {
headers.setContentDisposition(mCacheResult.contentdisposition);
}
+
+ if (!TextUtils.isEmpty(mCacheResult.crossDomain)) {
+ headers.setXPermittedCrossDomainPolicies(mCacheResult.crossDomain);
+ }
}
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 4f680e5..d19805e 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -99,6 +99,7 @@
String location;
String encoding;
String contentdisposition;
+ String crossDomain;
// these fields are NOT saved to the database
InputStream inStream;
@@ -733,6 +734,11 @@
ret.contentdisposition = contentDisposition;
}
+ String crossDomain = headers.getXPermittedCrossDomainPolicies();
+ if (crossDomain != null) {
+ ret.crossDomain = crossDomain;
+ }
+
// lastModified and etag may be set back to http header. So they can't
// be empty string.
String lastModified = headers.getLastModified();
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 2c24757..44f5d2b 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -127,6 +127,9 @@
private Headers mHeaders;
+ private final String mUsername;
+ private final String mPassword;
+
// =========================================================================
// Public functions
// =========================================================================
@@ -134,11 +137,13 @@
public static LoadListener getLoadListener(Context context,
BrowserFrame frame, String url, int nativeLoader,
boolean synchronous, boolean isMainPageLoader,
- boolean isMainResource, boolean userGesture, long postIdentifier) {
+ boolean isMainResource, boolean userGesture, long postIdentifier,
+ String username, String password) {
sNativeLoaderCount += 1;
return new LoadListener(context, frame, url, nativeLoader, synchronous,
- isMainPageLoader, isMainResource, userGesture, postIdentifier);
+ isMainPageLoader, isMainResource, userGesture, postIdentifier,
+ username, password);
}
public static int getNativeLoaderCount() {
@@ -147,7 +152,8 @@
LoadListener(Context context, BrowserFrame frame, String url,
int nativeLoader, boolean synchronous, boolean isMainPageLoader,
- boolean isMainResource, boolean userGesture, long postIdentifier) {
+ boolean isMainResource, boolean userGesture, long postIdentifier,
+ String username, String password) {
if (DebugFlags.LOAD_LISTENER) {
Log.v(LOGTAG, "LoadListener constructor url=" + url);
}
@@ -163,6 +169,8 @@
mIsMainResourceLoader = isMainResource;
mUserGesture = userGesture;
mPostIdentifier = postIdentifier;
+ mUsername = username;
+ mPassword = password;
}
/**
@@ -402,7 +410,7 @@
// if we tried to authenticate ourselves last time
if (mAuthHeader != null) {
- // we failed, if we must to authenticate again now and
+ // we failed, if we must authenticate again now and
// we have a proxy-ness match
mAuthFailed = (mustAuthenticate &&
isProxyAuthRequest == mAuthHeader.isProxy());
@@ -652,7 +660,13 @@
if (mAuthHeader != null &&
(Network.getInstance(mContext).isValidProxySet() ||
!mAuthHeader.isProxy())) {
- Network.getInstance(mContext).handleAuthRequest(this);
+ // If this is the first attempt to authenticate, try again with the username and
+ // password supplied in the URL, if present.
+ if (!mAuthFailed && mUsername != null && mPassword != null) {
+ makeAuthResponse(mUsername, mPassword);
+ } else {
+ Network.getInstance(mContext).handleAuthRequest(this);
+ }
return;
}
break; // use default
@@ -844,37 +858,8 @@
+ " username: " + username
+ " password: " + password);
}
-
- // create and queue an authentication-response
if (username != null && password != null) {
- if (mAuthHeader != null && mRequestHandle != null) {
- mAuthHeader.setUsername(username);
- mAuthHeader.setPassword(password);
-
- int scheme = mAuthHeader.getScheme();
- if (scheme == HttpAuthHeader.BASIC) {
- // create a basic response
- boolean isProxy = mAuthHeader.isProxy();
-
- mRequestHandle.setupBasicAuthResponse(isProxy,
- username, password);
- } else {
- if (scheme == HttpAuthHeader.DIGEST) {
- // create a digest response
- boolean isProxy = mAuthHeader.isProxy();
-
- String realm = mAuthHeader.getRealm();
- String nonce = mAuthHeader.getNonce();
- String qop = mAuthHeader.getQop();
- String algorithm = mAuthHeader.getAlgorithm();
- String opaque = mAuthHeader.getOpaque();
-
- mRequestHandle.setupDigestAuthResponse
- (isProxy, username, password, realm,
- nonce, qop, algorithm, opaque);
- }
- }
- }
+ makeAuthResponse(username, password);
} else {
// Commit whatever data we have and tear down the loader.
commitLoad();
@@ -882,6 +867,35 @@
}
}
+ void makeAuthResponse(String username, String password) {
+ if (mAuthHeader == null || mRequestHandle == null) {
+ return;
+ }
+
+ mAuthHeader.setUsername(username);
+ mAuthHeader.setPassword(password);
+
+ int scheme = mAuthHeader.getScheme();
+ if (scheme == HttpAuthHeader.BASIC) {
+ // create a basic response
+ boolean isProxy = mAuthHeader.isProxy();
+
+ mRequestHandle.setupBasicAuthResponse(isProxy, username, password);
+ } else if (scheme == HttpAuthHeader.DIGEST) {
+ // create a digest response
+ boolean isProxy = mAuthHeader.isProxy();
+
+ String realm = mAuthHeader.getRealm();
+ String nonce = mAuthHeader.getNonce();
+ String qop = mAuthHeader.getQop();
+ String algorithm = mAuthHeader.getAlgorithm();
+ String opaque = mAuthHeader.getOpaque();
+
+ mRequestHandle.setupDigestAuthResponse(isProxy, username, password,
+ realm, nonce, qop, algorithm, opaque);
+ }
+ }
+
/**
* This is called when a request can be satisfied by the cache, however,
* the cache result could be a redirect. In this case we need to issue
@@ -1599,7 +1613,7 @@
// from http thread. Then it is called again from WebViewCore thread
// after the load is completed. So make sure the queue is cleared but
// don't set it to null.
- for (int size = mMessageQueue.size(); size > 0; size--) {
+ while (!mMessageQueue.isEmpty()) {
handleMessage(mMessageQueue.remove(0));
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 714ae70..d8ec19a 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1483,10 +1483,8 @@
/**
* Load the given data into the WebView, use the provided URL as the base
* URL for the content. The base URL is the URL that represents the page
- * that is loaded through this interface. As such, it is used for the
- * history entry and to resolve any relative URLs. The failUrl is used if
- * browser fails to load the data provided. If it is empty or null, and the
- * load fails, then no history entry is created.
+ * that is loaded through this interface. As such, it is used to resolve any
+ * relative URLs. The historyUrl is used for the history entry.
* <p>
* Note for post 1.0. Due to the change in the WebKit, the access to asset
* files through "file:///android_asset/" for the sub resources is more
@@ -1501,10 +1499,10 @@
* @param mimeType The MIMEType of the data. i.e. text/html. If null,
* defaults to "text/html"
* @param encoding The encoding of the data. i.e. utf-8, us-ascii
- * @param failUrl URL to use if the content fails to load or null.
+ * @param historyUrl URL to use as the history entry. Can be null.
*/
public void loadDataWithBaseURL(String baseUrl, String data,
- String mimeType, String encoding, String failUrl) {
+ String mimeType, String encoding, String historyUrl) {
if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
loadData(data, mimeType, encoding);
@@ -1516,7 +1514,7 @@
arg.mData = data;
arg.mMimeType = mimeType;
arg.mEncoding = encoding;
- arg.mFailUrl = failUrl;
+ arg.mHistoryUrl = historyUrl;
mWebViewCore.sendMessage(EventHub.LOAD_DATA, arg);
clearTextEntry(false);
}
@@ -1900,7 +1898,7 @@
// Expects x in view coordinates
private int pinLocX(int x) {
if (mInOverScrollMode) return x;
- return pinLoc(x, getViewWidth(), computeHorizontalScrollRange());
+ return pinLoc(x, getViewWidth(), computeRealHorizontalScrollRange());
}
// Expects y in view coordinates
@@ -4320,7 +4318,7 @@
" up/down= " + mMinDY + " " + mMaxDY);
}
- int docRight = computeHorizontalScrollRange();
+ int docRight = computeRealHorizontalScrollRange();
int viewLeft = getScrollX();
int viewRight = viewLeft + getWidth();
mStartX = x;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 4e949dc..410227b 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -627,7 +627,7 @@
String mData;
String mMimeType;
String mEncoding;
- String mFailUrl;
+ String mHistoryUrl;
}
static class CursorData {
@@ -981,7 +981,7 @@
loadParams.mData,
loadParams.mMimeType,
loadParams.mEncoding,
- loadParams.mFailUrl);
+ loadParams.mHistoryUrl);
break;
case STOP_LOADING:
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index a75e6f0..b18419d 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -51,9 +51,10 @@
// 7 -> 8 Move cache to its own db
// 8 -> 9 Store both scheme and host when storing passwords
// 9 -> 10 Update httpauth table UNIQUE
- private static final int CACHE_DATABASE_VERSION = 3;
+ private static final int CACHE_DATABASE_VERSION = 4;
// 1 -> 2 Add expires String
// 2 -> 3 Add content-disposition
+ // 3 -> 4 Add crossdomain (For x-permitted-cross-domain-policies header)
private static WebViewDatabase mInstance = null;
@@ -126,6 +127,8 @@
private static final String CACHE_CONTENTDISPOSITION_COL = "contentdisposition";
+ private static final String CACHE_CROSSDOMAIN_COL = "crossdomain";
+
// column id strings for "password" table
private static final String PASSWORD_HOST_COL = "host";
@@ -166,6 +169,7 @@
private static int mCacheLocationColIndex;
private static int mCacheContentLengthColIndex;
private static int mCacheContentDispositionColIndex;
+ private static int mCacheCrossDomainColIndex;
private static int mCacheTransactionRefcount;
@@ -269,6 +273,8 @@
.getColumnIndex(CACHE_CONTENTLENGTH_COL);
mCacheContentDispositionColIndex = mCacheInserter
.getColumnIndex(CACHE_CONTENTDISPOSITION_COL);
+ mCacheCrossDomainColIndex = mCacheInserter
+ .getColumnIndex(CACHE_CROSSDOMAIN_COL);
}
}
@@ -378,6 +384,7 @@
+ " TEXT," + CACHE_HTTP_STATUS_COL + " INTEGER, "
+ CACHE_LOCATION_COL + " TEXT, " + CACHE_CONTENTLENGTH_COL
+ " INTEGER, " + CACHE_CONTENTDISPOSITION_COL + " TEXT, "
+ + CACHE_CROSSDOMAIN_COL + " TEXT,"
+ " UNIQUE (" + CACHE_URL_COL + ") ON CONFLICT REPLACE);");
mCacheDatabase.execSQL("CREATE INDEX cacheUrlIndex ON cache ("
+ CACHE_URL_COL + ")");
@@ -620,7 +627,7 @@
Cursor cursor = null;
final String query = "SELECT filepath, lastmodify, etag, expires, "
+ "expiresstring, mimetype, encoding, httpstatus, location, contentlength, "
- + "contentdisposition FROM cache WHERE url = ?";
+ + "contentdisposition, crossdomain FROM cache WHERE url = ?";
try {
cursor = mCacheDatabase.rawQuery(query, new String[] { url });
if (cursor.moveToFirst()) {
@@ -636,6 +643,7 @@
ret.location = cursor.getString(8);
ret.contentLength = cursor.getLong(9);
ret.contentdisposition = cursor.getString(10);
+ ret.crossDomain = cursor.getString(11);
return ret;
}
} catch (IllegalStateException e) {
@@ -684,6 +692,7 @@
mCacheInserter.bind(mCacheContentLengthColIndex, c.contentLength);
mCacheInserter.bind(mCacheContentDispositionColIndex,
c.contentdisposition);
+ mCacheInserter.bind(mCacheCrossDomainColIndex, c.crossDomain);
mCacheInserter.execute();
}
diff --git a/core/java/android/widget/HeaderViewListAdapter.java b/core/java/android/widget/HeaderViewListAdapter.java
index 981996a..e2a269e 100644
--- a/core/java/android/widget/HeaderViewListAdapter.java
+++ b/core/java/android/widget/HeaderViewListAdapter.java
@@ -28,19 +28,24 @@
* associated data objects.
*<p>This is intended as a base class; you will probably not need to
* use this class directly in your own code.
- *
*/
public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {
- private ListAdapter mAdapter;
+ private final ListAdapter mAdapter;
// These two ArrayList are assumed to NOT be null.
- // They are indeed created when declared in ListView and then shared.
+ // They are indeed created when declared in ListView and then shared.
ArrayList<ListView.FixedViewInfo> mHeaderViewInfos;
ArrayList<ListView.FixedViewInfo> mFooterViewInfos;
+
+ // Used as a placeholder in case the provided info views are indeed null.
+ // Currently only used by some CTS tests, which may be removed.
+ static final ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST =
+ new ArrayList<ListView.FixedViewInfo>();
+
boolean mAreAllFixedViewsSelectable;
- private boolean mIsFilterable;
+ private final boolean mIsFilterable;
public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,
ArrayList<ListView.FixedViewInfo> footerViewInfos,
@@ -48,8 +53,17 @@
mAdapter = adapter;
mIsFilterable = adapter instanceof Filterable;
- mHeaderViewInfos = headerViewInfos;
- mFooterViewInfos = footerViewInfos;
+ if (headerViewInfos == null) {
+ mHeaderViewInfos = EMPTY_INFO_LIST;
+ } else {
+ mHeaderViewInfos = headerViewInfos;
+ }
+
+ if (footerViewInfos == null) {
+ mFooterViewInfos = EMPTY_INFO_LIST;
+ } else {
+ mFooterViewInfos = footerViewInfos;
+ }
mAreAllFixedViewsSelectable =
areAllListInfosSelectable(mHeaderViewInfos)
@@ -130,43 +144,53 @@
}
public boolean isEnabled(int position) {
+ // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
int numHeaders = getHeadersCount();
- if (mAdapter != null && position >= numHeaders) {
- int adjPosition = position - numHeaders;
- int adapterCount = mAdapter.getCount();
- if (adjPosition >= adapterCount) {
- return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable;
- } else {
- return mAdapter.isEnabled(adjPosition);
- }
- } else if (position < numHeaders) {
+ if (position < numHeaders) {
return mHeaderViewInfos.get(position).isSelectable;
}
- return true;
+
+ // Adapter
+ final int adjPosition = position - numHeaders;
+ int adapterCount = 0;
+ if (mAdapter != null) {
+ adapterCount = mAdapter.getCount();
+ if (adjPosition < adapterCount) {
+ return mAdapter.isEnabled(adjPosition);
+ }
+ }
+
+ // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
+ return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable;
}
public Object getItem(int position) {
+ // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
int numHeaders = getHeadersCount();
- if (mAdapter != null && position >= numHeaders) {
- int adjPosition = position - numHeaders;
- int adapterCount = mAdapter.getCount();
- if (adjPosition >= adapterCount) {
- return mFooterViewInfos.get(adjPosition - adapterCount).data;
- } else {
- return mAdapter.getItem(adjPosition);
- }
- } else if (position < numHeaders) {
+ if (position < numHeaders) {
return mHeaderViewInfos.get(position).data;
}
- return null;
+
+ // Adapter
+ final int adjPosition = position - numHeaders;
+ int adapterCount = 0;
+ if (mAdapter != null) {
+ adapterCount = mAdapter.getCount();
+ if (adjPosition < adapterCount) {
+ return mAdapter.getItem(adjPosition);
+ }
+ }
+
+ // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
+ return mFooterViewInfos.get(adjPosition - adapterCount).data;
}
public long getItemId(int position) {
int numHeaders = getHeadersCount();
if (mAdapter != null && position >= numHeaders) {
int adjPosition = position - numHeaders;
- int adapterCnt = mAdapter.getCount();
- if (adjPosition < adapterCnt) {
+ int adapterCount = mAdapter.getCount();
+ if (adjPosition < adapterCount) {
return mAdapter.getItemId(adjPosition);
}
}
@@ -181,19 +205,24 @@
}
public View getView(int position, View convertView, ViewGroup parent) {
+ // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
int numHeaders = getHeadersCount();
- if (mAdapter != null && position >= numHeaders) {
- int adjPosition = position - numHeaders;
- int adapterCount = mAdapter.getCount();
- if (adjPosition >= adapterCount) {
- return mFooterViewInfos.get(adjPosition - adapterCount).view;
- } else {
- return mAdapter.getView(adjPosition, convertView, parent);
- }
- } else if (position < numHeaders) {
+ if (position < numHeaders) {
return mHeaderViewInfos.get(position).view;
}
- return null;
+
+ // Adapter
+ final int adjPosition = position - numHeaders;
+ int adapterCount = 0;
+ if (mAdapter != null) {
+ adapterCount = mAdapter.getCount();
+ if (adjPosition < adapterCount) {
+ return mAdapter.getView(adjPosition, convertView, parent);
+ }
+ }
+
+ // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
+ return mFooterViewInfos.get(adjPosition - adapterCount).view;
}
public int getItemViewType(int position) {
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 702ce0a..06da5fa 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -372,11 +372,12 @@
private boolean inChild(int x, int y) {
if (getChildCount() > 0) {
+ final int scrollX = mScrollX;
final View child = getChildAt(0);
return !(y < child.getTop()
|| y >= child.getBottom()
- || x < child.getLeft()
- || x >= child.getRight());
+ || x < child.getLeft() - scrollX
+ || x >= child.getRight() - scrollX);
}
return false;
}
@@ -410,7 +411,13 @@
* Locally do absolute value. mLastMotionX is set to the x value
* of the down event.
*/
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ final int activePointerId = mActivePointerId;
+ if (activePointerId == INVALID_POINTER) {
+ // If we don't have a valid id, the touch down wasn't on content.
+ break;
+ }
+
+ final int pointerIndex = ev.findPointerIndex(activePointerId);
final float x = ev.getX(pointerIndex);
final int xDiff = (int) Math.abs(x - mLastMotionX);
if (xDiff > mTouchSlop) {
@@ -449,6 +456,9 @@
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
+ if (mScroller.springback(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
+ invalidate();
+ }
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
@@ -480,21 +490,22 @@
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
- /*
- * If being flinged and user touches, stop the fling. isFinished
- * will be false if being flinged.
- */
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
-
final float x = ev.getX();
if (!(mIsBeingDragged = inChild((int) x, (int) ev.getY()))) {
return false;
}
+ /*
+ * If being flinged and user touches, stop the fling. isFinished
+ * will be false if being flinged.
+ */
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+
// Remember where the motion event started
mLastMotionX = x;
+ mActivePointerId = ev.getPointerId(0);
break;
}
case MotionEvent.ACTION_MOVE:
@@ -538,6 +549,19 @@
}
}
break;
+ case MotionEvent.ACTION_CANCEL:
+ if (mIsBeingDragged && getChildCount() > 0) {
+ if (mScroller.springback(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) {
+ invalidate();
+ }
+ mActivePointerId = INVALID_POINTER;
+ mIsBeingDragged = false;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+ break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
diff --git a/core/java/android/widget/ListAdapter.java b/core/java/android/widget/ListAdapter.java
index a035145..0fd2e70 100644
--- a/core/java/android/widget/ListAdapter.java
+++ b/core/java/android/widget/ListAdapter.java
@@ -36,6 +36,9 @@
/**
* Returns true if the item at the specified position is not a separator.
* (A separator is a non-selectable, non-clickable item).
+ *
+ * The result is unspecified if position is invalid. An {@link ArrayIndexOutOfBoundsException}
+ * should be thrown in that case for fast failure.
*
* @param position Index of the item
* @return True if the item is not a separator
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index f009432..36d244f 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -370,9 +370,10 @@
private boolean inChild(int x, int y) {
if (getChildCount() > 0) {
+ final int scrollY = mScrollY;
final View child = getChildAt(0);
- return !(y < child.getTop()
- || y >= child.getBottom()
+ return !(y < child.getTop() - scrollY
+ || y >= child.getBottom() - scrollY
|| x < child.getLeft()
|| x >= child.getRight());
}
@@ -408,7 +409,13 @@
* Locally do absolute value. mLastMotionY is set to the y value
* of the down event.
*/
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ final int activePointerId = mActivePointerId;
+ if (activePointerId == INVALID_POINTER) {
+ // If we don't have a valid id, the touch down wasn't on content.
+ break;
+ }
+
+ final int pointerIndex = ev.findPointerIndex(activePointerId);
final float y = ev.getY(pointerIndex);
final int yDiff = (int) Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop) {
@@ -446,6 +453,9 @@
/* Release the drag */
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
+ if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
+ invalidate();
+ }
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
@@ -477,19 +487,19 @@
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
- /*
- * If being flinged and user touches, stop the fling. isFinished
- * will be false if being flinged.
- */
- if (!mScroller.isFinished()) {
- mScroller.abortAnimation();
- }
-
final float y = ev.getY();
if (!(mIsBeingDragged = inChild((int) ev.getX(), (int) y))) {
return false;
}
+ /*
+ * If being flinged and user touches, stop the fling. isFinished
+ * will be false if being flinged.
+ */
+ if (!mScroller.isFinished()) {
+ mScroller.abortAnimation();
+ }
+
// Remember where the motion event started
mLastMotionY = y;
mActivePointerId = ev.getPointerId(0);
@@ -536,6 +546,19 @@
}
}
break;
+ case MotionEvent.ACTION_CANCEL:
+ if (mIsBeingDragged && getChildCount() > 0) {
+ if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) {
+ invalidate();
+ }
+ mActivePointerId = INVALID_POINTER;
+ mIsBeingDragged = false;
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ }
+ break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5546666..7f8e854 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -704,10 +704,10 @@
#if defined(WITH_JIT)
/* Minimal profile threshold to trigger JIT compilation */
- char jitThresholdBuf[sizeof("-Xthreshold:") + PROPERTY_VALUE_MAX];
+ char jitThresholdBuf[sizeof("-Xjitthreshold:") + PROPERTY_VALUE_MAX];
property_get("dalvik.vm.jit.threshold", propBuf, "");
if (strlen(propBuf) > 0) {
- strcpy(jitThresholdBuf, "-Xthreshold:");
+ strcpy(jitThresholdBuf, "-Xjitthreshold:");
strcat(jitThresholdBuf, propBuf);
opt.optionString = jitThresholdBuf;
mOptions.add(opt);
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index b6f3997..b41bad0 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -164,8 +164,11 @@
using namespace android;
class NinePatchPeeker : public SkImageDecoder::Peeker {
+ SkImageDecoder* fHost;
public:
- NinePatchPeeker() {
+ NinePatchPeeker(SkImageDecoder* host) {
+ // the host lives longer than we do, so a raw ptr is safe
+ fHost = host;
fPatchIsValid = false;
}
@@ -197,6 +200,19 @@
// fPatch.sizeLeft, fPatch.sizeTop,
// fPatch.sizeRight, fPatch.sizeBottom);
fPatchIsValid = true;
+
+ // now update our host to force index or 32bit config
+ // 'cause we don't want 565 predithered, since as a 9patch, we know
+ // we will be stretched, and therefore we want to dither afterwards.
+ static const SkBitmap::Config gNo565Pref[] = {
+ SkBitmap::kIndex8_Config,
+ SkBitmap::kIndex8_Config,
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kARGB_8888_Config,
+ SkBitmap::kARGB_8888_Config,
+ };
+ fHost->setPrefConfigTable(gNo565Pref);
} else {
fPatch = NULL;
}
@@ -364,7 +380,7 @@
decoder->setSampleSize(sampleSize);
decoder->setDitherImage(doDither);
- NinePatchPeeker peeker;
+ NinePatchPeeker peeker(decoder);
JavaPixelAllocator javaAllocator(env, reportSizeToVM);
SkBitmap* bitmap = new SkBitmap;
Res_png_9patch dummy9Patch;
diff --git a/core/res/assets/webkit/togglePluginBg.png b/core/res/assets/webkit/togglePluginBg.png
deleted file mode 100644
index 2c65acb..0000000
--- a/core/res/assets/webkit/togglePluginBg.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.png b/core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.png
index dc3e1f9..6ba42db 100644
--- a/core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.png
+++ b/core/res/res/drawable-hdpi/keyboard_key_feedback_background.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png b/core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png
index c67ed53..4d0b6010 100644
--- a/core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png
+++ b/core/res/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png
Binary files differ
diff --git a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
index 7028d1a..48fe765 100644
--- a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
+++ b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
@@ -214,7 +214,6 @@
MockContentResolver mockResolver = new MockContentResolver();
final TestContext testContext = new TestContext(mockResolver, getContext());
- SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<accounts>\n"
@@ -230,7 +229,7 @@
fos.write(accountsFileData);
accountInfoFile.finishWrite(fos);
- engine.clearAndReadState();
+ SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, authority1);
assertEquals(1, syncs.size());
@@ -245,7 +244,7 @@
assertEquals(sync3, syncs.get(0));
accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
- + "<accounts version=\"1\">\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"
@@ -268,7 +267,7 @@
assertEquals(0, syncs.size());
accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
- + "<accounts version=\"1\">\n"
+ + "<accounts version=\"2\">\n"
+ "<authority id=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\">\n"
+ "<periodicSync period=\"1000\" />\n"
+ "</authority>"
@@ -299,6 +298,89 @@
assertEquals(1, syncs.size());
assertEquals(sync3s, syncs.get(0));
}
+
+ @SmallTest
+ public void testAuthorityRenaming() throws Exception {
+ final Account account1 = new Account("acc1", "type1");
+ final Account account2 = new Account("acc2", "type2");
+ final String authorityContacts = "contacts";
+ final String authorityCalendar = "calendar";
+ final String authorityOther = "other";
+ final String authorityContactsNew = "com.android.contacts";
+ final String authorityCalendarNew = "com.android.calendar";
+
+ MockContentResolver mockResolver = new MockContentResolver();
+
+ final TestContext testContext = new TestContext(mockResolver, getContext());
+
+ byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<accounts>\n"
+ + "<authority id=\"0\" account=\"acc1\" type=\"type1\" authority=\"contacts\" />\n"
+ + "<authority id=\"1\" account=\"acc1\" type=\"type1\" authority=\"calendar\" />\n"
+ + "<authority id=\"2\" account=\"acc1\" type=\"type1\" authority=\"other\" />\n"
+ + "<authority id=\"3\" account=\"acc2\" type=\"type2\" authority=\"contacts\" />\n"
+ + "<authority id=\"4\" account=\"acc2\" type=\"type2\" authority=\"calendar\" />\n"
+ + "<authority id=\"5\" account=\"acc2\" type=\"type2\" authority=\"other\" />\n"
+ + "<authority id=\"6\" account=\"acc2\" type=\"type2\" enabled=\"false\""
+ + " authority=\"com.android.calendar\" />\n"
+ + "<authority id=\"7\" account=\"acc2\" type=\"type2\" enabled=\"false\""
+ + " authority=\"com.android.contacts\" />\n"
+ + "</accounts>\n").getBytes();
+
+ File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
+ 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);
+
+ assertEquals(false, engine.getSyncAutomatically(account1, authorityContacts));
+ assertEquals(false, engine.getSyncAutomatically(account1, authorityCalendar));
+ assertEquals(true, engine.getSyncAutomatically(account1, authorityOther));
+ assertEquals(true, engine.getSyncAutomatically(account1, authorityContactsNew));
+ assertEquals(true, engine.getSyncAutomatically(account1, authorityCalendarNew));
+
+ assertEquals(false, engine.getSyncAutomatically(account2, authorityContacts));
+ assertEquals(false, engine.getSyncAutomatically(account2, authorityCalendar));
+ assertEquals(true, engine.getSyncAutomatically(account2, authorityOther));
+ assertEquals(false, engine.getSyncAutomatically(account2, authorityContactsNew));
+ assertEquals(false, engine.getSyncAutomatically(account2, authorityCalendarNew));
+ }
+
+ @SmallTest
+ public void testSyncableMigration() throws Exception {
+ final Account account = new Account("acc", "type");
+
+ MockContentResolver mockResolver = new MockContentResolver();
+
+ final TestContext testContext = new TestContext(mockResolver, getContext());
+
+ byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<accounts>\n"
+ + "<authority id=\"0\" account=\"acc\" authority=\"other1\" />\n"
+ + "<authority id=\"1\" account=\"acc\" type=\"type\" authority=\"other2\" />\n"
+ + "<authority id=\"2\" account=\"acc\" type=\"type\" syncable=\"false\""
+ + " authority=\"other3\" />\n"
+ + "<authority id=\"3\" account=\"acc\" type=\"type\" syncable=\"true\""
+ + " authority=\"other4\" />\n"
+ + "</accounts>\n").getBytes();
+
+ File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync");
+ 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);
+
+ assertEquals(-1, engine.getIsSyncable(account, "other1"));
+ assertEquals(1, engine.getIsSyncable(account, "other2"));
+ assertEquals(0, engine.getIsSyncable(account, "other3"));
+ assertEquals(1, engine.getIsSyncable(account, "other4"));
+ }
}
class TestContext extends ContextWrapper {
diff --git a/docs/html/guide/appendix/g-app-intents.jd b/docs/html/guide/appendix/g-app-intents.jd
index 2846859..df9d29b 100644
--- a/docs/html/guide/appendix/g-app-intents.jd
+++ b/docs/html/guide/appendix/g-app-intents.jd
@@ -1,8 +1,11 @@
page.title=Intents List: Invoking Google Applications on Android Devices
@jd:body
+<div class="sidebox-wrapper">
<div class="sidebox">
-For more information about intents, see the <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>.
+For more information about intents, see the <a
+href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>.
+</div>
</div>
<p>The table below lists the intents that your application can send, to invoke Google applications on Android devices in certain ways. For each action/uri pair, the table describes how the receiving Google application handles the intent. </p>
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index 8fa4cec..22c099f 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -55,7 +55,7 @@
<h3 id="dev-phone-1">Android Dev Phone 1</h3>
<div class="sidebox-wrapper">
-<div class="sidebox-inner">
+<div class="sidebox">
<p>Selected specs for Android Dev Phone 1:</p>
<ul>
<li>Touch screen</li>
diff --git a/docs/html/guide/developing/tools/avd.jd b/docs/html/guide/developing/tools/avd.jd
index 06b1245..acebb7e 100644
--- a/docs/html/guide/developing/tools/avd.jd
+++ b/docs/html/guide/developing/tools/avd.jd
@@ -93,7 +93,7 @@
<h2 id="creating">Creating an AVD</h2>
<div class="sidebox-wrapper">
-<div class="sidebox-inner">
+<div class="sidebox">
<p>The Android SDK does not include any preconfigured AVDs, so
you need to create an AVD before you can run any application in the emulator
(even the Hello World application).</p>
diff --git a/docs/html/guide/developing/tools/draw9patch.jd b/docs/html/guide/developing/tools/draw9patch.jd
index 9607ae7..61da1e0 100644
--- a/docs/html/guide/developing/tools/draw9patch.jd
+++ b/docs/html/guide/developing/tools/draw9patch.jd
@@ -7,9 +7,8 @@
the section on Nine-patch in the
<a href="{@docRoot}guide/topics/resources/available-resources.html#ninepatch">Nine-patch Images</a> topic.</p>
-<div class="sidebox" style="width:auto"><br/>
-<img src="{@docRoot}images/draw9patch-norm.png" alt="" height="300" width="341" />
-</div>
+<img src="{@docRoot}images/draw9patch-norm.png" style="float:right" alt="" height="300" width="341"
+/>
<p>Here's a quick guide to create a Nine-patch graphic using the Draw 9-patch tool.
You'll need the PNG image with which you'd like to create a NinePatch.</p>
@@ -39,9 +38,8 @@
A previously saved 9-patch file (<code>*.9.png</code>) will be loaded as-is,
with no drawing area added, because it already exists.</p>
-<div class="sidebox" style="width:auto"><br/>
-<img src="{@docRoot}images/draw9patch-bad.png" alt="" height="300" width="341" />
-</div>
+<img src="{@docRoot}images/draw9patch-bad.png" style="float:right" alt="" height="300" width="341"
+/>
<p>Optional controls include:</p>
<ul>
diff --git a/docs/html/guide/practices/design/responsiveness.jd b/docs/html/guide/practices/design/responsiveness.jd
index 1d5a235..8a4e7cf 100644
--- a/docs/html/guide/practices/design/responsiveness.jd
+++ b/docs/html/guide/practices/design/responsiveness.jd
@@ -23,8 +23,8 @@
this with basic performance, which was described above as a <em>method</em>-level
concern.)</p>
-<div class="sidebox" style="margin-top:1em;border:0;">
-<div style="border:0;background-color:#fff;padding:15px;padding-right:2em;margin:0;">
+<div class="sidebox-wrapper">
+<div class="sidebox">
<img src="{@docRoot}images/anr.png" width="240" height="320" alt="Screenshot of ANR dialog box">
<p style="margin-top:.5em;padding:.5em;">An ANR dialog displayed to the user.</p>
</div>
diff --git a/docs/html/guide/publishing/preparing.jd b/docs/html/guide/publishing/preparing.jd
index 5357166..c1c6351 100644
--- a/docs/html/guide/publishing/preparing.jd
+++ b/docs/html/guide/publishing/preparing.jd
@@ -176,10 +176,13 @@
<h3 id="mapsApiKey">7. Register for a Maps API Key, if your application is using
MapView elements</h3>
-<div class="sidebox" style="margin-bottom:.5em;padding:1em;"><p>
+<div class="sidebox-wrapper">
+<div class="sidebox"><p>
For complete information about getting a Maps API Key, see <a
href="http://code.google.com/android/add-ons/google-apis/mapkey.html">
-Obtaining a Maps API Key</a>.</p></div>
+Obtaining a Maps API Key</a>.</p>
+</div>
+</div>
<p>If your application uses one or more Mapview elements, you will need to
register your application with the Google
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index f36b684..7a8dd59 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -220,7 +220,7 @@
<h2 id="AppWidgetProvider">Using the AppWidgetProvider Class</h2>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+<div class="sidebox">
<p>You must declare your AppWidgetProvider class implementation as a broadcast receiver
using the <code><receiver></code> element in the AndroidManifest (see
<a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p>
diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd
index c10af8e..807c7ff 100644
--- a/docs/html/guide/topics/fundamentals.jd
+++ b/docs/html/guide/topics/fundamentals.jd
@@ -1180,7 +1180,7 @@
</p>
<div class="sidebox-wrapper">
-<div class="sidebox-inner">
+<div class="sidebox">
<h2>Calling into the superclass</h2>
<p>
An implementation of any activity lifecycle method should always first
diff --git a/docs/html/guide/topics/intents/intents-filters.jd b/docs/html/guide/topics/intents/intents-filters.jd
index 110721d..bd1d694 100644
--- a/docs/html/guide/topics/intents/intents-filters.jd
+++ b/docs/html/guide/topics/intents/intents-filters.jd
@@ -392,7 +392,7 @@
</p>
<div class="sidebox-wrapper">
-<div class="sidebox-inner">
+<div class="sidebox">
<h2>Filters and security</h2>
<p>An intent filter cannot be relied on for security. While it opens a
component to receiving only certain kinds of implicit intents, it does
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index 662efbf..f114895 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -41,6 +41,7 @@
<p>The Android framework gives you the flexibility to use either or both of these methods for declaring and managing your application's UI. For example, you could declare your application's default layouts in XML, including the screen elements that will appear in them and their properties. You could then add code in your application that would modify the state of the screen objects, including those declared in XML, at run time. </p>
+<div class="sidebox-wrapper">
<div class="sidebox">
<ul>
<li>The <a href="{@docRoot}sdk/eclipse-adt.html">ADT
@@ -54,6 +55,7 @@
<li>The <a href="{@docRoot}guide/developing/tools/layoutopt.html">layoutopt</a> tool lets
you quickly analyze your layouts and hierarchies for inefficiencies or other problems.</li>
</div>
+</div>
<p>The advantage to declaring your UI in XML is that it enables you to better separate the presentation of your application from the code that controls its behavior. Your UI descriptions are external to your application code, which means that you can modify or adapt it without having to modify your source code and recompile. For example, you can create XML layouts for different screen orientations, different device screen sizes, and different languages. Additionally, declaring the layout in XML makes it easier to visualize the structure of your UI, so it's easier to debug problems. As such, this document focuses on teaching you how to declare your layout in XML. If you're
interested in instantiating View objects at runtime, refer to the {@link android.view.ViewGroup} and
@@ -69,10 +71,15 @@
<h2 id="write">Write the XML</h2>
-<div class="sidebox"><p>For your convenience, the API reference documentation for UI related classes lists the available XML attributes that correspond to the class methods, including inherited attributes.</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<p>For your convenience, the API reference documentation for UI related classes
+lists the available XML attributes that correspond to the class methods, including inherited
+attributes.</p>
<p>To learn more about the available XML elements and attributes, as well as the format of the XML file, see <a
href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Layout Resources</a>.</p>
- </div>
+</div>
+</div>
<p>Using Android's XML vocabulary, you can quickly design UI layouts and the screen elements they contain, in the same way you create web pages in HTML — with a series of nested elements. </p>
diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd
index efb55a2..3a57afa 100644
--- a/docs/html/guide/topics/ui/how-android-draws.jd
+++ b/docs/html/guide/topics/ui/how-android-draws.jd
@@ -18,12 +18,14 @@
siblings drawn in the order they appear in the tree.
</p>
+<div class="sidebox-wrapper">
<div class="sidebox">
<p>The framework will not draw Views that are not in the invalid region, and also
will take care of drawing the Views background for you.</p>
<p>You can force a View to draw, by calling <code>{@link android.view.View#invalidate()}</code>.
</p>
</div>
+</div>
<p>
Drawing the layout is a two pass process: a measure pass and a layout pass. The measuring
@@ -50,11 +52,13 @@
as to how much space they each get, the parent will intervene and set the rules on the second pass).
</p>
- <div class="sidebox"><p>
+<div class="sidebox-wrapper">
+<div class="sidebox"><p>
To initiate a layout, call <code>{@link android.view.View#requestLayout}</code>. This method is typically
called by a View on itself when it believes that is can no longer fit within
its current bounds.</p>
- </div>
+</div>
+</div>
<p>
The measure pass uses two classes to communicate dimensions. The
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
index 494bda8..abcf6be 100644
--- a/docs/html/guide/topics/ui/index.jd
+++ b/docs/html/guide/topics/ui/index.jd
@@ -107,7 +107,7 @@
<p>For more on building a UI layout, read <a href="declaring-layout.html">Declaring Layout</a>.
<div class="sidebox-wrapper">
-<div class="sidebox-inner">
+<div class="sidebox">
<p><b>Tip:</b> You can also draw View and ViewGroups objects in Java code,
using the <code>{@link android.view.ViewGroup#addView(View)}</code> methods
to dynamically insert new View and ViewGroup objects.</p>
diff --git a/docs/html/guide/topics/ui/layout-objects.jd b/docs/html/guide/topics/ui/layout-objects.jd
index 345e9b3..8b2792d 100644
--- a/docs/html/guide/topics/ui/layout-objects.jd
+++ b/docs/html/guide/topics/ui/layout-objects.jd
@@ -55,6 +55,7 @@
"more important" than both the others, so it gets half the total remaining space, while the first two
share the rest equally.</p>
+<div class="sidebox-wrapper">
<div class="sidebox">
<p><strong>Tip</strong>: To create a proportionate size
layout on the screen, create a container view group object with the
@@ -64,6 +65,7 @@
to each child, depending on what proportion of the screen each should
have.</p>
</div>
+</div>
<p>The following two forms represent a {@link android.widget.LinearLayout LinearLayout} with a set of elements: a
button, some labels and text boxes. The text boxes have their width set to <var>fill_parent</var>; other
diff --git a/docs/html/guide/topics/views/ui-xml.jd b/docs/html/guide/topics/views/ui-xml.jd
index 8ae599c..bcfa562 100644
--- a/docs/html/guide/topics/views/ui-xml.jd
+++ b/docs/html/guide/topics/views/ui-xml.jd
@@ -21,11 +21,16 @@
example, the EditText element has a <code>text</code> attribute that corresponds to
EditText.setText. </p>
-<div class="sidebox"><p>For your convenience, the API reference documentation for UI related classes lists the available XML attributes that correspond to the class methods, including inherited attributes.</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<p>For your convenience, the API reference documentation for UI related classes
+lists the available XML attributes that correspond to the class methods, including inherited
+attributes.</p>
<p>To learn more about the available XML elements and attributes, as well as the format of the XML file, see <a
href="{@docRoot}reference/available-resources.html#layoutresources">Layout Resources</a>.</p>
- </div>
+</div>
+</div>
<p>Using Android's XML vocabulary, you can quickly design UI layouts and the screen elements they contain, in the same way you create HTML files — as a series of nested tags. </p>
diff --git a/docs/html/guide/topics/wireless/bluetooth.jd b/docs/html/guide/topics/wireless/bluetooth.jd
index 80aa0d7..a8ff007 100644
--- a/docs/html/guide/topics/wireless/bluetooth.jd
+++ b/docs/html/guide/topics/wireless/bluetooth.jd
@@ -466,7 +466,8 @@
the {@link android.bluetooth.BluetoothServerSocket} can (and should) be
discarded, unless you want to accept more connections.</p>
-<div class="sidebox-wrapper"><div class="sidebox-inner">
+<div class="sidebox-wrapper">
+<div class="sidebox">
<h2>About UUID</h2>
<p>A Universally Unique Identifier (UUID) is a standardized 128-bit format for a string
@@ -476,7 +477,8 @@
use with your application, you can use one of the many random UUID generators on
the web, then initialize a {@link java.util.UUID} with {@link
java.util.UUID#fromString(String)}.</p>
-</div></div>
+</div>
+</div>
<p>Here's the basic procedure to set up a server socket and accept a
connection:</p>
diff --git a/docs/html/guide/tutorials/hello-world.jd b/docs/html/guide/tutorials/hello-world.jd
index f6b54ff..6e315b2 100644
--- a/docs/html/guide/tutorials/hello-world.jd
+++ b/docs/html/guide/tutorials/hello-world.jd
@@ -35,7 +35,7 @@
<h2 id="avd">Create an AVD</h2>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>To learn more about how to use AVDs and the options
available to you, refer to the
<a href="{@docRoot}guide/developing/tools/avd.html">Android
@@ -243,7 +243,7 @@
</ol>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>To learn more about creating and editing run configurations in Eclipse, refer to
<a href="{@docRoot}guide/developing/eclipse-adt.html#RunConfig">Developing In Eclipse,
with ADT</a>.</p>
@@ -357,12 +357,14 @@
your application requires. In addition to layout files, resources also include assets
such as images, sounds, and localized strings.</p>
+<div class="sidebox-wrapper">
<div class="sidebox">
<h2>Landscape layout</h2>
<p>When you want a different design for landscape, put your layout XML file
inside /res/layout-land. Android will automatically look here when the layout changes.
Without this special landscape layout defined, Android will stretch the default layout.</p>
</div>
+</div>
<p>The Eclipse plugin automatically creates one of these layout files for you: main.xml.
In the "Hello World" application you just completed, this file was ignored and you created a
@@ -478,12 +480,12 @@
because it lets you quickly and interactively locate the specific reference
you're looking for.</p>
-<p>It's possible yours looks slightly different than this (perhaps the hexadecimal values are different).
+<p>It's possible yours looks slighly different than this (perhaps the hexadecimal values are different).
For now, notice the inner class named "layout", and its
member field "main". The Eclipse plugin noticed the XML
layout file named main.xml and generated a class for it here. As you add other
resources to your project (such as strings in the <code>res/values/string.xml</code> file or drawables inside
-the <code>res/drawable/</code> directory) you'll see <code>R.java</code> change to keep up.</p>
+the <code>res/drawable/</code> direcory) you'll see <code>R.java</code> change to keep up.</p>
<p>When not using Eclipse, this class file will be generated for you at build time (with the Ant tool).</p>
<p><em>You should never edit this file by hand.</em></p>
</div>
diff --git a/docs/html/guide/tutorials/notepad/index.jd b/docs/html/guide/tutorials/notepad/index.jd
index 6319fad..f569314 100644
--- a/docs/html/guide/tutorials/notepad/index.jd
+++ b/docs/html/guide/tutorials/notepad/index.jd
@@ -20,7 +20,7 @@
concepts in Android development. If you want to add more complex features to
your application, you can examine the code in an alternative implementation
of a Note Pad application, in the
-<a href="{@docRoot}guide/samples/index.html">Sample Code</a> section. </p>
+<a href="{@docRoot}resources/samples/index.html">Sample Code</a> section. </p>
<a name="who"></a>
@@ -46,7 +46,7 @@
Fundamentals</a> before continuing. </p>
<p>This tutorial also builds on the introductory information provided in the
-<a href="{@docRoot}guide/tutorials/hello-world.html">Hello World</a>
+<a href="{@docRoot}resources/tutorials/hello-world.html">Hello World</a>
tutorial, which explains how to set up your Eclipse environment
for building Android applications. We recommend you complete the Hello World
tutorial before starting this one.</p>
@@ -81,7 +81,7 @@
table lists the
tutorial examples and describes what each covers. ">
<tr>
- <th width="120"><a href="{@docRoot}guide/tutorials/notepad/notepad-ex1.html">Exercise
+ <th width="120"><a href="{@docRoot}resources/tutorials/notepad/notepad-ex1.html">Exercise
1</a></th>
<td>Start here. Construct a simple notes list that lets the user add new notes but not
edit them. Demonstrates the basics of <code>ListActivity</code> and creating
@@ -89,7 +89,7 @@
menu options. Uses a SQLite database to store the notes.</td>
</tr>
<tr>
- <th><a href="{@docRoot}guide/tutorials/notepad/notepad-ex2.html">Exercise 2</a></th>
+ <th><a href="{@docRoot}resources/tutorials/notepad/notepad-ex2.html">Exercise 2</a></th>
<td>Add a second Activity to the
application. Demonstrates constructing a
new Activity, adding it to the Android manifest, passing data between the
@@ -98,13 +98,13 @@
<code>startActivityForResult()</code>.</td>
</tr>
<tr>
- <th><a href="{@docRoot}guide/tutorials/notepad/notepad-ex3.html">Exercise 3</a></th>
+ <th><a href="{@docRoot}resources/tutorials/notepad/notepad-ex3.html">Exercise 3</a></th>
<td>Add handling of life-cycle events to
the application, to let it
maintain application state across the life cycle. </td>
</tr>
<tr>
- <th><a href="{@docRoot}guide/tutorials/notepad/notepad-extra-credit.html">Extra
+ <th><a href="{@docRoot}resources/tutorials/notepad/notepad-extra-credit.html">Extra
Credit</a></th>
<td>Demonstrates how to use the Eclipse
debugger and how you can use it to
@@ -119,11 +119,11 @@
<ul>
<li>For a lighter but broader introduction to concepts not covered in the
tutorial,
-take a look at <a href="{@docRoot}guide/appendix/faq/commontasks.html">Common Android Tasks</a>.</li>
+take a look at <a href="{@docRoot}resources/faq/commontasks.html">Common Android Tasks</a>.</li>
<li>The Android SDK includes a variety of fully functioning sample applications
that make excellent opportunities for further learning. You can find the sample
applications in the <code>samples/</code> directory of your downloaded SDK, or browser them
-here, in the <a href="{@docRoot}guide/samples/index.html">Sample Code</a> section.</li>
+here, in the <a href="{@docRoot}resources/samples/index.html">Sample Code</a> section.</li>
<li>This tutorial draws from the full Notepad application included in the
<code>samples/</code> directory of the SDK, though it does not match it exactly.
When you are done with the tutorial,
diff --git a/docs/html/guide/tutorials/notepad/notepad-ex1.jd b/docs/html/guide/tutorials/notepad/notepad-ex1.jd
index b5173b8..cf7765e 100644
--- a/docs/html/guide/tutorials/notepad/notepad-ex1.jd
+++ b/docs/html/guide/tutorials/notepad/notepad-ex1.jd
@@ -33,7 +33,7 @@
<p><code>Notepadv1</code> is a project that is provided as a starting point. It
takes care of some of the boilerplate work that you have already seen if you
- followed the <a href="{@docRoot}guide/tutorials/hello-world.html">Hello,
+ followed the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello,
World</a> tutorial.</p>
<ol>
@@ -44,7 +44,7 @@
In the New Android Project dialog, select <strong>Create project from existing source</strong>.</li>
<li>
Click <strong>Browse</strong> and navigate to where you copied the <code>NotepadCodeLab</code>
- (downloaded during <a href="{@docRoot}guide/tutorials/notepad/index.html#preparing">setup</a>)
+ (downloaded during <a href="{@docRoot}resources/tutorials/notepad/index.html#preparing">setup</a>)
and select <code>Notepadv1</code>.</li>
<li>
The Project Name and other properties should be automatically filled for you.
@@ -64,23 +64,22 @@
<h2>Step 2</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Accessing and modifying data</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">For this
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Accessing and modifying data</h2>
+ <p>For this
exercise, we are using a SQLite database to store our data. This is useful
if only <em>your</em> application will need to access or modify the data. If you wish for
other activities to access or modify the data, you have to expose the data using a
{@link android.content.ContentProvider ContentProvider}.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">If you are interested, you can find out more about
- <a href="{@docRoot}guide/topics/providers/content-providers.html">content providers</a> or the whole
+ <p>If you are interested, you can find out more about
+ <a href="{@docRoot}guide/topics/providers/content-providers.html">content providers</a> or the
+whole
subject of <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>.
The NotePad sample in the <code>samples/</code> folder of the SDK also has an example of how
to create a ContentProvider.</p>
</div>
+ </div>
<p>Take a look at the <code>NotesDbAdapter</code> class — this class is provided to
encapsulate data access to a SQLite database that will hold our notes data
@@ -137,25 +136,22 @@
<h2 style="clear:right;">Step 3</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Layouts and activities</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Most Activity classes will have a layout associated with them. The layout
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Layouts and activities</h2>
+ <p>Most Activity classes will have a layout associated with them. The layout
will be the "face" of the Activity to the user. In this case our layout will
take over the whole screen and provide a list of notes.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Full screen layouts are not the only option for an Activity however. You
+ <p>Full screen layouts are not the only option for an Activity however. You
might also want to use a <a
-href="{@docRoot}guide/appendix/faq/commontasks.html#floatingorfull">floating
+href="{@docRoot}resources/faq/commontasks.html#floatingorfull">floating
layout</a> (for example, a <a
-href="{@docRoot}guide/appendix/faq/commontasks.html#dialogsandalerts">dialog
+href="{@docRoot}resources/faq/commontasks.html#dialogsandalerts">dialog
or alert</a>),
or perhaps you don't need a layout at all (the Activity will be invisible
to the user unless you specify some kind of layout for it to use).</p>
- </div>
+ </div>
+ </div>
<p>Open the <code>notepad_list.xml</code> file in <code>res/layout</code>
and
@@ -233,23 +229,22 @@
<h2 style="clear:right;">Step 5</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Resources and the R class</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">The folders under res/ in the Eclipse project are for resources.
- There is a <a href="{@docRoot}guide/appendix/faq/commontasks.html#filelist">specific structure</a> to the
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Resources and the R class</h2>
+ <p>The folders under res/ in the Eclipse project are for resources.
+ There is a <a href="{@docRoot}resources/faq/commontasks.html#filelist">specific structure</a>
+to the
folders and files under res/.</p>
- <p style="padding-left:.5em;font-size:12px;
-margin:0; padding:.0em .5em .5em 1em;">Resources defined in these folders and files will have
+ <p>Resources defined in these folders and files will have
corresponding entries in the R class allowing them to be easily accessed
and used from your application. The R class is automatically generated using the contents
of the res/ folder by the eclipse plugin (or by aapt if you use the command line tools).
Furthermore, they will be bundled and deployed for you as part of the application.</p>
</p>
</div>
+ </div>
+
<p>To make the list of notes in the ListView, we also need to define a View for each row:</p>
<ol>
<li>
@@ -373,20 +368,18 @@
<h2>Step 9</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">More on menus</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">The notepad application we are constructing only scratches the
- surface with <a href="{@docRoot}guide/appendix/faq/commontasks.html#addmenuitems">menus</a>. </p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">You can also <a href="{@docRoot}guide/appendix/faq/commontasks.html#menukeyshortcuts">add
-shortcut keys for menu items</a>, <a href="{@docRoot}guide/appendix/faq/commontasks.html#menukeyshortcuts">create
-submenus</a> and even <a href="{@docRoot}guide/appendix/faq/commontasks.html#addingtoothermenus">add
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>More about menus</h2>
+ <p>The notepad application we are constructing only scratches the
+ surface with <a href="{@docRoot}resources/faq/commontasks.html#addmenuitems">menus</a>. </p>
+ <p>You can also <a href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">add
+shortcut keys for menu items</a>, <a
+href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">create
+submenus</a> and even <a href="{@docRoot}resources/faq/commontasks.html#addingtoothermenus">add
menu items to other applications!</a>. </p>
</div>
+ </div>
<p>Fill out the body of the <code>onCreateOptionsMenu()</code> method.</p>
@@ -486,19 +479,17 @@
<h2>Step 12</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">List adapters</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Our example uses a {@link android.widget.SimpleCursorAdapter
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>List adapters</h2>
+ <p>Our example uses a {@link android.widget.SimpleCursorAdapter
SimpleCursorAdapter} to bind a database {@link android.database.Cursor Cursor}
into a ListView, and this is a common way to use a {@link android.widget.ListAdapter
ListAdapter}. Other options exist like {@link android.widget.ArrayAdapter ArrayAdapter} which
can be used to take a List or Array of in-memory data and bind it in to
a list as well.</p>
</div>
+ </div>
<p>Define the <code>fillData()</code> method:</p>
<p>This
diff --git a/docs/html/guide/tutorials/notepad/notepad-ex2.jd b/docs/html/guide/tutorials/notepad/notepad-ex2.jd
index 3b8fa0b..a945a62 100644
--- a/docs/html/guide/tutorials/notepad/notepad-ex2.jd
+++ b/docs/html/guide/tutorials/notepad/notepad-ex2.jd
@@ -1,11 +1,11 @@
-page.title=Notepad Exercise 2
+Rpage.title=Notepad Exercise 2
parent.title=Notepad Tutorial
parent.link=index.html
@jd:body
<p><em>In this exercise, you will add a second Activity to your notepad application, to let the user
-create and edit notes. You will also allow the user to delete existing notes through a context menu.
+create and edit notes. You will also allow the user to delete existing notes through a context menu.
The new Activity assumes responsibility for creating new notes by
collecting user input and packing it into a return Bundle provided by the intent. This exercise
demonstrates:</em></p>
@@ -55,7 +55,7 @@
</li>
<li>
There are also a couple of new overridden methods
- (<code>onCreateContextMenu()</code>, <code>onContextItemSelected()</code>,
+ (<code>onCreateContextMenu()</code>, <code>onContextItemSelected()</code>,
<code>onListItemClick()</code> and <code>onActivityResult()</code>)
which we will be filling in below.
</li>
@@ -63,19 +63,20 @@
<h2>Step 2</h2>
-
+<div class="sidebox-wrapper">
<div class="sidebox">
<p>Context menus should always be used when performing actions upon specific elements in the UI.
When you register a View to a context menu, the context menu is revealed by performing a "long-click"
on the UI component (press and hold the touchscreen or highlight and hold down the selection key for about two seconds).</p>
</div>
+</div>
<p>First, let's create the context menu that will allow users to delete individual notes.
Open the Notepadv2 class.</p>
<ol>
<li>In order for each list item in the ListView to register for the context menu, we call
- <code>registerForContextMenu()</code> and pass it our ListView. So, at the very end of
+ <code>registerForContextMenu()</code> and pass it our ListView. So, at the very end of
the <code>onCreate()</code> method add this line:
<pre>registerForContextMenu(getListView());</pre>
<p>Because our Activity extends the ListActivity class, <code>getListView()</code> will return us
@@ -91,7 +92,7 @@
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}</pre>
- <p>The <code>onCreateContextMenu()</code> callback some passes other information in addition to the Menu object,
+ <p>The <code>onCreateContextMenu()</code> callback passes some other information in addition to the Menu object,
such as the View that has been triggered for the menu and
an extra object that may contain additional information about the object selected. However, we don't care about
these here, because we only have one kind of object in the Activity that uses context menus. In the next
@@ -102,7 +103,7 @@
<h2>Step 3</h2>
<p>Now that the we've registered our ListView for a context menu and defined our context menu item, we need
to handle the callback when it is selected. For this, we need to identify the list ID of the
- selected item, then delete it. So fill in the
+ selected item, then delete it. So fill in the
<code>onContextItemSelected()</code> method like this:</p>
<pre>
public boolean onContextItemSelected(MenuItem item) {
@@ -122,26 +123,23 @@
can now be deleted.</p>
<h2 style="clear:right;">Step 4</h2>
-<div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Starting Other Activities</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">In this example our Intent uses a class name specifically.
- As well as
- <a href="{@docRoot}guide/appendix/faq/commontasks.html#intentexamples">starting intents</a> in
- classes we already know about, be they in our own application or another
- application, we can also create Intents without knowing exactly which
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Starting Other Activities</h2>
+ <p>In this example our Intent uses a class name specifically.
+ As well as
+ <a href="{@docRoot}resources/faq/commontasks.html#intentexamples">starting intents</a> in
+ classes we already know about, be they in our own application or another
+ application, we can also create Intents without knowing exactly which
application will handle it.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">For example, we might want to open a page in a
+ <p>For example, we might want to open a page in a
browser, and for this we still use
an Intent. But instead of specifying a class to handle it, we use
a predefined Intent constant, and a content URI that describes what we
want to do. See {@link android.content.Intent
android.content.Intent} for more information.</p>
-</div>
+ </div>
+ </div>
<p>Fill in the body of the <code>createNote()</code> method:
<p>Create a new <code>Intent</code> to create a note
@@ -155,7 +153,7 @@
<code>NoteEdit</code>. Since the Intent class will need to communicate with the Android
operating system to route requests, we also have to provide a Context (<code>this</code>).</p>
<p>The <code>startActivityForResult()</code> method fires the Intent in a way that causes a method
- in our Activity to be called when the new Activity is completed. The method in our Activity
+ in our Activity to be called when the new Activity is completed. The method in our Activity
that receives the callback is called
<code>onActivityResult()</code> and we will implement it in a later step. The other way
to call an Activity is using <code>startActivity()</code> but this is a "fire-and-forget" way
@@ -164,7 +162,7 @@
<p>Don't worry about the fact that <code>NoteEdit</code> doesn't exist yet,
we will fix that soon. </p>
</li>
-
+
<h2>Step 5</h2>
@@ -180,7 +178,7 @@
interested in is the <code>position</code> that the user selected. We use
this to get the data from the correct row, and bundle it up to send to
the <code>NoteEdit</code> Activity.</p>
- <p>In our implementation of the callback, the method creates an
+ <p>In our implementation of the callback, the method creates an
<code>Intent</code> to edit the note using
the <code>NoteEdit</code> class. It then adds data into the extras Bundle of
the Intent, which will be passed to the called Activity. We use it
@@ -207,7 +205,7 @@
</li>
<li>
The details of the note are pulled out from our query Cursor, which we move to the
- proper position for the element that was selected in the list, with
+ proper position for the element that was selected in the list, with
the <code>moveToPosition()</code> method.</li>
<li>With the extras added to the Intent, we invoke the Intent on the
<code>NoteEdit</code> class by passing <code>startActivityForResult()</code>
@@ -219,7 +217,7 @@
variable is much more efficient than accessing a field in the Dalvik VM, so by doing this
we make only one access to the field, and five accesses to the local variable, making the
routine much more efficient. It is recommended that you use this optimization when possible.</p>
-
+
<h2>Step 6</h2>
@@ -243,7 +241,7 @@
<li><code>intent</code> — this is an Intent created by the Activity returning
results. It can be used to return data in the Intent "extras."
</li>
- </ul>
+ </ul>
<p>The combination of <code>startActivityForResult()</code> and
<code>onActivityResult()</code> can be thought of as an asynchronous RPC
(remote procedure call) and forms the recommended way for an Activity to invoke
@@ -277,7 +275,7 @@
<code>ACTIVITY_EDIT</code> activity results in this method.
</li>
<li>
- In the case of a create, we pull the title and body from the extras (retrieved from the
+ In the case of a create, we pull the title and body from the extras (retrieved from the
returned Intent) and use them to create a new note.
</li>
<li>
@@ -288,29 +286,27 @@
<code>fillData()</code> at the end ensures everything is up to date .
</li>
</ul>
-
+
<h2>Step 7</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">The Art of Layout</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">The provided
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>The Art of Layout</h2>
+ <p>The provided
note_edit.xml layout file is the most sophisticated one in the application we will be building,
but that doesn't mean it is even close to the kind of sophistication you will be likely to want
in real Android applications.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">Creating a
+ <p>Creating a
good UI is part art and part science, and the rest is work. Mastery of <a
href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a> is an essential part of creating
a good looking Android application.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Take a look at the
- <a href="{@docRoot}guide/tutorials/views/index.html">Hello Views</a>
+ <p>Take a look at the
+ <a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a>
for some example layouts and how to use them. The ApiDemos sample project is also a
great resource from which to learn how to create different layouts.</p>
</div>
+ </div>
<p>Open the file <code>note_edit.xml</code> that has been provided and take a
look at it. This is the UI code for the Note Editor.</p>
@@ -335,7 +331,7 @@
<code>layout_weight</code> specified, so it takes up the minimum space
required to render. If the <code>layout_weight</code> of each of the two
text edit elements is set to 1, the remaining width in the parent layout will
- be split equally between them (because we claim they are equally important).
+ be split equally between them (because we claim they are equally important).
If the first one has a <code>layout_weight</code> of 1
and the second has a <code>layout_weight</code> of 2, then one third of the
remaining space will be given to the first, and two thirds to the
@@ -373,7 +369,7 @@
<code>onCreate(Bundle)</code> — and check the box next to it.</li>
<li>Click <strong>OK</strong>.<p>The method should now appear in your class.</p></li>
</ol>
-
+
<h2>Step 9</h2>
<p>Fill in the body of the <code>onCreate()</code> method for <code>NoteEdit</code>.</p>
@@ -388,7 +384,7 @@
<p>We can then unbundle the values that were passed in to the Activity
with the extras Bundle attached to the calling Intent. We'll use them to pre-populate
the title and body text edit views so that the user can edit them.
- Then we will grab and store the <code>mRowId</code> so we can keep
+ Then we will grab and store the <code>mRowId</code> so we can keep
track of what note the user is editing.</p>
<ol>
@@ -406,14 +402,14 @@
mTitleText = (EditText) findViewById(R.id.title);
mBodyText = (EditText) findViewById(R.id.body);
Button confirmButton = (Button) findViewById(R.id.confirm);</pre>
- <p>Note that <code>mTitleText</code> and <code>mBodyText</code> are member
+ <p>Note that <code>mTitleText</code> and <code>mBodyText</code> are member
fields (you need to declare them at the top of the class definition).</p>
</li>
<li>At the top of the class, declare a <code>Long mRowId</code> private field to store
the current <code>mRowId</code> being edited (if any).
</li>
- <li>Continuing inside <code>onCreate()</code>,
- add code to initialize the <code>title</code>, <code>body</code> and
+ <li>Continuing inside <code>onCreate()</code>,
+ add code to initialize the <code>title</code>, <code>body</code> and
<code>mRowId</code> from the extras Bundle in
the Intent (if it is present):<br>
<pre>
@@ -423,7 +419,7 @@
String title = extras.getString(NotesDbAdapter.KEY_TITLE);
String body = extras.getString(NotesDbAdapter.KEY_BODY);
mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
-
+
if (title != null) {
mTitleText.setText(title);
}
@@ -459,16 +455,16 @@
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
-
+
}
-
+
});</pre>
</li>
</ol>
<h2>Step 10</h2>
<p>Fill in the body of the <code>onClick()</code> method of the <code>OnClickListener</code> created in the last step.</p>
-
+
<p>This is the code that will be run when the user clicks on the
confirm button. We want this to grab the title and body text from the edit
text fields, and put them into the return Bundle so that they can be passed
@@ -483,7 +479,7 @@
constants defined in Notepadv2 as keys:<br>
<pre>
Bundle bundle = new Bundle();
-
+
bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString());
bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString());
if (mRowId != null) {
@@ -498,7 +494,7 @@
setResult(RESULT_OK, mIntent);
finish();</pre>
<ul>
- <li>The Intent is simply our data carrier that carries our Bundle
+ <li>The Intent is simply our data carrier that carries our Bundle
(with the title, body and mRowId).</li>
<li>The <code>setResult()</code> method is used to set the result
code and return Intent to be passed back to the
@@ -521,19 +517,19 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.note_edit);
-
+
mTitleText = (EditText) findViewById(R.id.title);
mBodyText = (EditText) findViewById(R.id.body);
-
+
Button confirmButton = (Button) findViewById(R.id.confirm);
-
+
mRowId = null;
Bundle extras = getIntent().getExtras();
if (extras != null) {
String title = extras.getString(NotesDbAdapter.KEY_TITLE);
String body = extras.getString(NotesDbAdapter.KEY_BODY);
mRowId = extras.getLong(NotesDbAdapter.KEY_ROWID);
-
+
if (title != null) {
mTitleText.setText(title);
}
@@ -541,12 +537,12 @@
mBodyText.setText(body);
}
}
-
+
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Bundle bundle = new Bundle();
-
+
bundle.putString(NotesDbAdapter.KEY_TITLE, mTitleText.getText().toString());
bundle.putString(NotesDbAdapter.KEY_BODY, mBodyText.getText().toString());
if (mRowId != null) {
@@ -562,24 +558,22 @@
}</pre>
</li>
</ol>
-
+
<h2>Step 11</h2>
-<div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">The All-Important Android Manifest File</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">The AndroidManifest.xml file is the way in which Android sees your
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>The All-Important Android Manifest File</h2>
+ <p>The AndroidManifest.xml file is the way in which Android sees your
application. This file defines the category of the application, where
it shows up (or even if it shows up) in the launcher or settings, what
activities, services, and content providers it defines, what intents it can
receive, and more. </p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">For more information, see the reference document
- <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></p>
- </div>
+ <p>For more information, see the reference document
+ <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml
+File</a></p>
+ </div>
+ </div>
<p>Finally, the new Activity has to be defined in the manifest file:</p>
<p>Before the new Activity can be seen by Android, it needs its own
@@ -597,10 +591,10 @@
</li>
<li>Click the <strong>Application</strong> tab at the bottom of the Manifest editor.</li>
<li>Click <strong>Add...</strong> in the Application Nodes section.
- <p>If you see a dialog with radiobuttons at the top, select the top radio button:
+ <p>If you see a dialog with radiobuttons at the top, select the top radio button:
"Create a new element at the top level, in Application".</p></li>
<li>Make sure "(A) Activity" is selected in the selection pane of the dialog, and click <strong>OK</strong>.</li>
- <li>Click on the new "Activity" node, in the Application Nodes section, then
+ <li>Click on the new "Activity" node, in the Application Nodes section, then
type <code>.NoteEdit</code> into the <em>Name*</em>
field to the right. Press Return/Enter.</li>
</ol>
@@ -608,28 +602,28 @@
file, have a look around at some of the other options available (but be careful not to select
them otherwise they will be added to your Manifest). This editor should help you understand
and alter the AndroidManifest.xml file as you move on to more advanced Android applications.</p>
-
+
<p class="note">If you prefer to edit this file directly, simply open the
<code>AndroidManifest.xml</code> file and look at the source (use the
<code>AndroidManifest.xml</code> tab in the eclipse editor to see the source code directly).
Then edit the file as follows:<br>
- <code><activity android:name=".NoteEdit"></activity></code><br><br>
+ <code><activity android:name=".NoteEdit" /></code><br><br>
This should be placed just below the line that reads:<br>
<code></activity></code> for the <code>.Notepadv2</code> activity.</p>
<h2 style="clear:right;">Step 12</h2>
<p>Now Run it!</p>
-<p>You should now be able to add real notes from
-the menu, as well as delete an existing one. Notice that in order to delete, you must
+<p>You should now be able to add real notes from
+the menu, as well as delete an existing one. Notice that in order to delete, you must
first use the directional controls on the device to highlight the note.
-Furthermore, selecting a note title from the list should bring up the note
-editor to let you edit it. Press confirm when finished to save the changes
+Furthermore, selecting a note title from the list should bring up the note
+editor to let you edit it. Press confirm when finished to save the changes
back to the database.
<h2>Solution and Next Steps</h2>
-<p>You can see the solution to this exercise in <code>Notepadv2Solution</code>
+<p>You can see the solution to this exercise in <code>Notepadv2Solution</code>
from the zip file to compare with your own.</p>
<p>Now try editing a note, and then hitting the back button on the emulator
instead of the confirm button (the back button is below the menu button). You
diff --git a/docs/html/guide/tutorials/notepad/notepad-ex3.jd b/docs/html/guide/tutorials/notepad/notepad-ex3.jd
index 8737280..573500f 100644
--- a/docs/html/guide/tutorials/notepad/notepad-ex3.jd
+++ b/docs/html/guide/tutorials/notepad/notepad-ex3.jd
@@ -36,7 +36,7 @@
<ol>
<li>Remove the code in <code>NoteEdit</code> that parses the title and body
- from the extras Bundle.
+ from the extras Bundle.
<p>Instead, we are going to use the <code>DBHelper</code> class
to access the notes from the database directly. All we need passed into the
NoteEdit Activity is a <code>mRowId</code> (but only if we are editing, if creating we pass
@@ -57,7 +57,7 @@
}</pre>
</li>
</ol>
-
+
<h2>Step 2</h2>
<p>Create a class field for a <code>NotesDbAdapter</code> at the top of the NoteEdit class:</p>
@@ -67,11 +67,11 @@
<pre>
mDbHelper = new NotesDbAdapter(this);<br>
mDbHelper.open();</pre>
-
+
<h2>Step 3</h2>
<p>In <code>NoteEdit</code>, we need to check the <var>savedInstanceState</var> for the
-<code>mRowId</code>, in case the note
+<code>mRowId</code>, in case the note
editing contains a saved state in the Bundle, which we should recover (this would happen
if our Activity lost focus and then restarted).</p>
<ol>
@@ -87,11 +87,11 @@
</pre>
with this:
<pre>
- mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID)
- : null;
+ mRowId = (savedInstanceState == null) ? null :
+ (Long) savedInstanceState.getSerializable(NotesDbAdapter.KEY_ROWID);
if (mRowId == null) {
- Bundle extras = getIntent().getExtras();
- mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
+ Bundle extras = getIntent().getExtras();
+ mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
: null;
}
</pre>
@@ -100,10 +100,15 @@
Note the null check for <code>savedInstanceState</code>, and we still need to load up
<code>mRowId</code> from the <code>extras</code> Bundle if it is not
provided by the <code>savedInstanceState</code>. This is a ternary operator shorthand
- to safely either use the value or null if it is not present.
+ to safely either use the value or null if it is not present.
+ </li>
+ <li>
+ Note the use of <code>Bundle.getSerializable()</code> instead of
+ <code>Bundle.getLong()</code>. The latter encoding returns a <code>long</code> primitive and
+ so can not be used to represent the case when <code>mRowId</code> is <code>null</code>.
</li>
</ol>
-
+
<h2>Step 4</h2>
<p>Next, we need to populate the fields based on the <code>mRowId</code> if we
@@ -126,38 +131,38 @@
}</pre>
<p>We will take care of storing the updates or new notes in the database
ourselves, using the life-cycle methods.</p>
-
+
<p>The whole <code>onCreate()</code> method should now look like this:</p>
<pre>
super.onCreate(savedInstanceState);
-
+
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();
-
+
setContentView(R.layout.note_edit);
-
+
mTitleText = (EditText) findViewById(R.id.title);
mBodyText = (EditText) findViewById(R.id.body);
-
+
Button confirmButton = (Button) findViewById(R.id.confirm);
-
-mRowId = savedInstanceState != null ? savedInstanceState.getLong(NotesDbAdapter.KEY_ROWID)
- : null;
+
+mRowId = (savedInstanceState == null) ? null :
+ (Long) savedInstanceState.getSerializable(NotesDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
- mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
+ mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
: null;
}
-
+
populateFields();
-
+
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
setResult(RESULT_OK);
finish();
}
-
+
});</pre>
<h2>Step 6</h2>
@@ -180,38 +185,36 @@
and re-create resources as dictated by the Activity life-cycle, so we don't need to worry about
doing that ourselves. After that, we just look up the title and body values from the Cursor
and populate the View elements with them.</p>
-
+
<h2>Step 7</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;margin-bottom:.5em;
- margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Why handling life-cycle events is important</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">If you are used to always having control in your applications, you
- might not understand why all this life-cycle work is necessary. The reason
- is that in Android, you are not in control of your Activity, the
- operating system is!</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">As we have already seen, the Android model is based around activities
- calling each other. When one Activity calls another, the current Activity
- is paused at the very least, and may be killed altogether if the
- system starts to run low on resources. If this happens, your Activity will
- have to store enough state to come back up later, preferably in the same
- state it was in when it was killed.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;padding:.0em .5em .5em 1em;">
- Android has a <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">well-defined life cycle</a>.
- Lifecycle events can happen even if you are not handing off control to
- another Activity explicitly. For example, perhaps a call comes in to the
- handset. If this happens, and your Activity is running, it will be swapped
- out while the call Activity takes over.</p>
- </div>
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Why handling life-cycle events is important</h2>
+ <p>If you are used to always having control in your applications, you
+ might not understand why all this life-cycle work is necessary. The reason
+ is that in Android, you are not in control of your Activity, the
+ operating system is!</p>
+ <p>As we have already seen, the Android model is based around activities
+ calling each other. When one Activity calls another, the current Activity
+ is paused at the very least, and may be killed altogether if the
+ system starts to run low on resources. If this happens, your Activity will
+ have to store enough state to come back up later, preferably in the same
+ state it was in when it was killed.</p>
+ <p>
+ Android has a <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">well-defined life
+cycle</a>.
+ Lifecycle events can happen even if you are not handing off control to
+ another Activity explicitly. For example, perhaps a call comes in to the
+ handset. If this happens, and your Activity is running, it will be swapped
+ out while the call Activity takes over.</p>
+ </div>
+ </div>
-<p>Still in the <code>NoteEdit</code> class, we now override the methods
- <code>onSaveInstanceState()</code>, <code>onPause()</code> and
- <code>onResume()</code>. These are our life-cycle methods
+<p>Still in the <code>NoteEdit</code> class, we now override the methods
+ <code>onSaveInstanceState()</code>, <code>onPause()</code> and
+ <code>onResume()</code>. These are our life-cycle methods
(along with <code>onCreate()</code> which we already have).</p>
<p><code>onSaveInstanceState()</code> is called by Android if the
@@ -241,8 +244,10 @@
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putLong(NotesDbAdapter.KEY_ROWID, mRowId);
+ saveState();
+ outState.putSerializable(NotesDbAdapter.KEY_ROWID, mRowId);
}</pre>
+ <p>We'll define <code>saveState()</code> next.</p>
</li>
<li><code>
onPause()</code>:
@@ -252,7 +257,6 @@
super.onPause();
saveState();
}</pre>
- <p>We'll define <code>saveState()</code> next.</p>
</li>
<li><code>
onResume()</code>:
@@ -264,6 +268,10 @@
}</pre>
</li>
</ol>
+<p>Note that <code>saveState()</code> must be called in both <code>onSaveInstanceState()</code>
+and <code>onPause()</code> to ensure that the data is saved. This is because there is no
+guarantee that <code>onSaveInstanceState()</code> will be called and because when it <em>is</em>
+called, it is called before <code>onPause()</code>.</p>
<h2 style="clear:right;">Step 8</h2>
@@ -301,19 +309,18 @@
necessary. The resulting method should look like this:</p>
<pre>
@Override
-protected void onActivityResult(int requestCode, int resultCode,
- Intent intent) {
+protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
fillData();
}</pre>
<p>Because the other class now does the work, all this has to do is refresh
the data.</p>
-
+
<h2>Step 10</h2>
<p>Also remove the lines which set the title and body from the
- <code>onListItemClick()</code> method (again they are no longer needed,
+ <code>onListItemClick()</code> method (again they are no longer needed,
only the <code>mRowId</code> is):</p>
<pre>
Cursor c = mNotesCursor;
@@ -344,13 +351,13 @@
other occurrences of <code>mNotesCursor</code> in your <code>fillData()</code> method.
</ol>
<p>
-Run it! (use <em>Run As -> Android Application</em> on the project right
+Run it! (use <em>Run As -> Android Application</em> on the project right
click menu again)</p>
<h2>Solution and Next Steps</h2>
<p>You can see the solution to this exercise in <code>Notepadv3Solution</code>
-from
+from
the zip file to compare with your own.</p>
<p>
When you are ready, move on to the <a href="notepad-extra-credit.html">Tutorial
diff --git a/docs/html/intl/ja/guide/publishing/preparing.jd b/docs/html/intl/ja/guide/publishing/preparing.jd
index f1e7b45..e232f3b 100644
--- a/docs/html/intl/ja/guide/publishing/preparing.jd
+++ b/docs/html/intl/ja/guide/publishing/preparing.jd
@@ -113,9 +113,13 @@
<h3 id="mapsApiKey">7. アプリケーションが MapView 要素を使用している場合は、Maps API キーに登録する</h3>
-<div class="sidebox" style="margin-bottom:.5em;padding:1em;"><p>
+<div class="sidebox-wrapper">
+<div class="sidebox"><p>
Maps API キーを取得する方法は、<a
-href="http://code.google.com/android/add-ons/google-apis/mapkey.html">Maps API キーの取得(英語のみ)</a> をご覧ください。</p></div>
+href="http://code.google.com/android/add-ons/google-apis/mapkey.html">Maps API キーの取得(英語のみ)</a>
+をご覧ください。</p>
+</div>
+</div>
<p>アプリケーションが Mapview 要素を使用する場合、アプリケーションを Google Maps サービスで登録し、Maps API キーを取得する必要があります。その後、MapView で Google Maps からデータを取得できるようになります。この処理を行うため、Maps サービスに署名証明書の MD5 フィンガープリントを提出します。 </p>
diff --git a/docs/html/intl/ja/guide/topics/fundamentals.jd b/docs/html/intl/ja/guide/topics/fundamentals.jd
index 247d076..d329a8c 100644
--- a/docs/html/intl/ja/guide/topics/fundamentals.jd
+++ b/docs/html/intl/ja/guide/topics/fundamentals.jd
@@ -613,7 +613,7 @@
</p>
<div class="sidebox-wrapper">
-<div class="sidebox-inner">
+<div class="sidebox">
<h2>スーパークラスの呼び出し</h2>
<p>
どのアクティビティ ライフサイクル メソッドの実装でも、必ず最初にスーパークラス バージョンを呼び出す必要があります。次に例を示します:
diff --git a/docs/html/intl/ja/guide/tutorials/hello-world.jd b/docs/html/intl/ja/guide/tutorials/hello-world.jd
index c12965c..647c828 100644
--- a/docs/html/intl/ja/guide/tutorials/hello-world.jd
+++ b/docs/html/intl/ja/guide/tutorials/hello-world.jd
@@ -25,7 +25,7 @@
<h2 id="avd">AVD の作成</h2>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>AVD の使用方法と使用可能なオプションについて詳しくは、<a href="{@docRoot}guide/developing/tools/avd.html">Android 仮想デバイス</a> のドキュメントを参照してください。</p>
</div>
</div>
@@ -155,7 +155,7 @@
</ol>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>Eclipse での起動構成の作成と編集について詳しくは、「<a href="{@docRoot}guide/developing/eclipse-adt.html#RunConfig">ADT を使用した Eclipse での開発</a>」を参照してください。</p>
</div>
</div>
@@ -232,11 +232,12 @@
<p>これらの XML レイアウト ファイルは、作成するプロジェクトの <code>res/layout/</code> ディレクトリ内に置かれます。「res」は「resources」の略で、アプリケーションに必要なコード以外のすべてのアセットがこのディレクトリに格納されます。リソースには、レイアウト ファイルの他に、画像、音声、ローカライズされた文字列などのアセットがあります。</p>
-
+<div class="sidebox-wrapper">
<div class="sidebox">
<h2>横表示レイアウト</h2>
<p>横表示の場合に異なるデザインで表示するには、レイアウト XML ファイルを /res/layout-land 内に入れます。Android 端末のレイアウトが横表示に変わると自動的にこのディレクトリが参照されます。このように横表示向けに定義されたレイアウトが存在しない場合、自動的にデフォルトのレイアウトが拡大して使用されます。</p>
</div>
+</div>
<p>Eclipse プラグインでは、このようなレイアウト ファイルの 1 つである「main.xml」が自動的に作成されます。先ほど「Hello World」アプリケーションを作成した際には、このファイルは無視してプログラマティックにレイアウトを作成しました。この作成方法は Android フレームワークについてより深く理解していただくことを意図したもので、実際にはほとんどの場合レイアウトはコードではなく XML ファイルで定義します。以下の手順では、既存のアプリケーションを変更して XML レイアウトが使用されるようにする方法を説明します。</p>
diff --git a/docs/html/intl/ja/resources/tutorials/hello-world.jd b/docs/html/intl/ja/resources/tutorials/hello-world.jd
index c12965c..0cda2fb 100644
--- a/docs/html/intl/ja/resources/tutorials/hello-world.jd
+++ b/docs/html/intl/ja/resources/tutorials/hello-world.jd
@@ -25,7 +25,7 @@
<h2 id="avd">AVD の作成</h2>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>AVD の使用方法と使用可能なオプションについて詳しくは、<a href="{@docRoot}guide/developing/tools/avd.html">Android 仮想デバイス</a> のドキュメントを参照してください。</p>
</div>
</div>
@@ -155,7 +155,7 @@
</ol>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>Eclipse での起動構成の作成と編集について詳しくは、「<a href="{@docRoot}guide/developing/eclipse-adt.html#RunConfig">ADT を使用した Eclipse での開発</a>」を参照してください。</p>
</div>
</div>
@@ -233,10 +233,12 @@
<p>これらの XML レイアウト ファイルは、作成するプロジェクトの <code>res/layout/</code> ディレクトリ内に置かれます。「res」は「resources」の略で、アプリケーションに必要なコード以外のすべてのアセットがこのディレクトリに格納されます。リソースには、レイアウト ファイルの他に、画像、音声、ローカライズされた文字列などのアセットがあります。</p>
+<div class="sidebox-wrapper">
<div class="sidebox">
<h2>横表示レイアウト</h2>
<p>横表示の場合に異なるデザインで表示するには、レイアウト XML ファイルを /res/layout-land 内に入れます。Android 端末のレイアウトが横表示に変わると自動的にこのディレクトリが参照されます。このように横表示向けに定義されたレイアウトが存在しない場合、自動的にデフォルトのレイアウトが拡大して使用されます。</p>
</div>
+</div>
<p>Eclipse プラグインでは、このようなレイアウト ファイルの 1 つである「main.xml」が自動的に作成されます。先ほど「Hello World」アプリケーションを作成した際には、このファイルは無視してプログラマティックにレイアウトを作成しました。この作成方法は Android フレームワークについてより深く理解していただくことを意図したもので、実際にはほとんどの場合レイアウトはコードではなく XML ファイルで定義します。以下の手順では、既存のアプリケーションを変更して XML レイアウトが使用されるようにする方法を説明します。</p>
diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd
index 58d1a16..6e315b2 100644
--- a/docs/html/resources/tutorials/hello-world.jd
+++ b/docs/html/resources/tutorials/hello-world.jd
@@ -35,7 +35,7 @@
<h2 id="avd">Create an AVD</h2>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>To learn more about how to use AVDs and the options
available to you, refer to the
<a href="{@docRoot}guide/developing/tools/avd.html">Android
@@ -243,7 +243,7 @@
</ol>
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+ <div class="sidebox">
<p>To learn more about creating and editing run configurations in Eclipse, refer to
<a href="{@docRoot}guide/developing/eclipse-adt.html#RunConfig">Developing In Eclipse,
with ADT</a>.</p>
@@ -357,12 +357,14 @@
your application requires. In addition to layout files, resources also include assets
such as images, sounds, and localized strings.</p>
+<div class="sidebox-wrapper">
<div class="sidebox">
<h2>Landscape layout</h2>
<p>When you want a different design for landscape, put your layout XML file
inside /res/layout-land. Android will automatically look here when the layout changes.
Without this special landscape layout defined, Android will stretch the default layout.</p>
</div>
+</div>
<p>The Eclipse plugin automatically creates one of these layout files for you: main.xml.
In the "Hello World" application you just completed, this file was ignored and you created a
diff --git a/docs/html/resources/tutorials/notepad/notepad-ex1.jd b/docs/html/resources/tutorials/notepad/notepad-ex1.jd
index b26440b..cf7765e 100644
--- a/docs/html/resources/tutorials/notepad/notepad-ex1.jd
+++ b/docs/html/resources/tutorials/notepad/notepad-ex1.jd
@@ -64,23 +64,22 @@
<h2>Step 2</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Accessing and modifying data</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">For this
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Accessing and modifying data</h2>
+ <p>For this
exercise, we are using a SQLite database to store our data. This is useful
if only <em>your</em> application will need to access or modify the data. If you wish for
other activities to access or modify the data, you have to expose the data using a
{@link android.content.ContentProvider ContentProvider}.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">If you are interested, you can find out more about
- <a href="{@docRoot}guide/topics/providers/content-providers.html">content providers</a> or the whole
+ <p>If you are interested, you can find out more about
+ <a href="{@docRoot}guide/topics/providers/content-providers.html">content providers</a> or the
+whole
subject of <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>.
The NotePad sample in the <code>samples/</code> folder of the SDK also has an example of how
to create a ContentProvider.</p>
</div>
+ </div>
<p>Take a look at the <code>NotesDbAdapter</code> class — this class is provided to
encapsulate data access to a SQLite database that will hold our notes data
@@ -137,17 +136,13 @@
<h2 style="clear:right;">Step 3</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Layouts and activities</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Most Activity classes will have a layout associated with them. The layout
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Layouts and activities</h2>
+ <p>Most Activity classes will have a layout associated with them. The layout
will be the "face" of the Activity to the user. In this case our layout will
take over the whole screen and provide a list of notes.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Full screen layouts are not the only option for an Activity however. You
+ <p>Full screen layouts are not the only option for an Activity however. You
might also want to use a <a
href="{@docRoot}resources/faq/commontasks.html#floatingorfull">floating
layout</a> (for example, a <a
@@ -155,7 +150,8 @@
or alert</a>),
or perhaps you don't need a layout at all (the Activity will be invisible
to the user unless you specify some kind of layout for it to use).</p>
- </div>
+ </div>
+ </div>
<p>Open the <code>notepad_list.xml</code> file in <code>res/layout</code>
and
@@ -233,23 +229,22 @@
<h2 style="clear:right;">Step 5</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Resources and the R class</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">The folders under res/ in the Eclipse project are for resources.
- There is a <a href="{@docRoot}resources/faq/commontasks.html#filelist">specific structure</a> to the
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Resources and the R class</h2>
+ <p>The folders under res/ in the Eclipse project are for resources.
+ There is a <a href="{@docRoot}resources/faq/commontasks.html#filelist">specific structure</a>
+to the
folders and files under res/.</p>
- <p style="padding-left:.5em;font-size:12px;
-margin:0; padding:.0em .5em .5em 1em;">Resources defined in these folders and files will have
+ <p>Resources defined in these folders and files will have
corresponding entries in the R class allowing them to be easily accessed
and used from your application. The R class is automatically generated using the contents
of the res/ folder by the eclipse plugin (or by aapt if you use the command line tools).
Furthermore, they will be bundled and deployed for you as part of the application.</p>
</p>
</div>
+ </div>
+
<p>To make the list of notes in the ListView, we also need to define a View for each row:</p>
<ol>
<li>
@@ -373,20 +368,18 @@
<h2>Step 9</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">More on menus</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">The notepad application we are constructing only scratches the
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>More about menus</h2>
+ <p>The notepad application we are constructing only scratches the
surface with <a href="{@docRoot}resources/faq/commontasks.html#addmenuitems">menus</a>. </p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">You can also <a href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">add
-shortcut keys for menu items</a>, <a href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">create
+ <p>You can also <a href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">add
+shortcut keys for menu items</a>, <a
+href="{@docRoot}resources/faq/commontasks.html#menukeyshortcuts">create
submenus</a> and even <a href="{@docRoot}resources/faq/commontasks.html#addingtoothermenus">add
menu items to other applications!</a>. </p>
</div>
+ </div>
<p>Fill out the body of the <code>onCreateOptionsMenu()</code> method.</p>
@@ -486,19 +479,17 @@
<h2>Step 12</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">List adapters</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Our example uses a {@link android.widget.SimpleCursorAdapter
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>List adapters</h2>
+ <p>Our example uses a {@link android.widget.SimpleCursorAdapter
SimpleCursorAdapter} to bind a database {@link android.database.Cursor Cursor}
into a ListView, and this is a common way to use a {@link android.widget.ListAdapter
ListAdapter}. Other options exist like {@link android.widget.ArrayAdapter ArrayAdapter} which
can be used to take a List or Array of in-memory data and bind it in to
a list as well.</p>
</div>
+ </div>
<p>Define the <code>fillData()</code> method:</p>
<p>This
diff --git a/docs/html/resources/tutorials/notepad/notepad-ex2.jd b/docs/html/resources/tutorials/notepad/notepad-ex2.jd
index 44a04ab..a945a62 100644
--- a/docs/html/resources/tutorials/notepad/notepad-ex2.jd
+++ b/docs/html/resources/tutorials/notepad/notepad-ex2.jd
@@ -63,12 +63,13 @@
<h2>Step 2</h2>
-
+<div class="sidebox-wrapper">
<div class="sidebox">
<p>Context menus should always be used when performing actions upon specific elements in the UI.
When you register a View to a context menu, the context menu is revealed by performing a "long-click"
on the UI component (press and hold the touchscreen or highlight and hold down the selection key for about two seconds).</p>
</div>
+</div>
<p>First, let's create the context menu that will allow users to delete individual notes.
Open the Notepadv2 class.</p>
@@ -122,26 +123,23 @@
can now be deleted.</p>
<h2 style="clear:right;">Step 4</h2>
-<div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Starting Other Activities</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">In this example our Intent uses a class name specifically.
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Starting Other Activities</h2>
+ <p>In this example our Intent uses a class name specifically.
As well as
<a href="{@docRoot}resources/faq/commontasks.html#intentexamples">starting intents</a> in
classes we already know about, be they in our own application or another
application, we can also create Intents without knowing exactly which
application will handle it.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">For example, we might want to open a page in a
+ <p>For example, we might want to open a page in a
browser, and for this we still use
an Intent. But instead of specifying a class to handle it, we use
a predefined Intent constant, and a content URI that describes what we
want to do. See {@link android.content.Intent
android.content.Intent} for more information.</p>
-</div>
+ </div>
+ </div>
<p>Fill in the body of the <code>createNote()</code> method:
<p>Create a new <code>Intent</code> to create a note
@@ -292,25 +290,23 @@
<h2>Step 7</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">The Art of Layout</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">The provided
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>The Art of Layout</h2>
+ <p>The provided
note_edit.xml layout file is the most sophisticated one in the application we will be building,
but that doesn't mean it is even close to the kind of sophistication you will be likely to want
in real Android applications.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0; padding:.0em .5em .5em 1em;">Creating a
+ <p>Creating a
good UI is part art and part science, and the rest is work. Mastery of <a
href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a> is an essential part of creating
a good looking Android application.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">Take a look at the
+ <p>Take a look at the
<a href="{@docRoot}resources/tutorials/views/index.html">Hello Views</a>
for some example layouts and how to use them. The ApiDemos sample project is also a
great resource from which to learn how to create different layouts.</p>
</div>
+ </div>
<p>Open the file <code>note_edit.xml</code> that has been provided and take a
look at it. This is the UI code for the Note Editor.</p>
@@ -565,20 +561,18 @@
<h2>Step 11</h2>
-<div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;
- margin-bottom:.5em;margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">The All-Important Android Manifest File</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">The AndroidManifest.xml file is the way in which Android sees your
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>The All-Important Android Manifest File</h2>
+ <p>The AndroidManifest.xml file is the way in which Android sees your
application. This file defines the category of the application, where
it shows up (or even if it shows up) in the launcher or settings, what
activities, services, and content providers it defines, what intents it can
receive, and more. </p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">For more information, see the reference document
- <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></p>
+ <p>For more information, see the reference document
+ <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml
+File</a></p>
+ </div>
</div>
<p>Finally, the new Activity has to be defined in the manifest file:</p>
diff --git a/docs/html/resources/tutorials/notepad/notepad-ex3.jd b/docs/html/resources/tutorials/notepad/notepad-ex3.jd
index 2da113f..573500f 100644
--- a/docs/html/resources/tutorials/notepad/notepad-ex3.jd
+++ b/docs/html/resources/tutorials/notepad/notepad-ex3.jd
@@ -189,30 +189,28 @@
<h2>Step 7</h2>
- <div class="sidebox" style="border:2px solid #FFFFDD;float:right;
- background-color:#FFFFEE;margin-right:0px;margin-bottom:.5em;
- margin-top:1em;padding:0em;width:240px;">
- <h2 style="border:0;font-size:12px;padding:.5em .5em .5em 1em;margin:0;
- background-color:#FFFFDD;">Why handling life-cycle events is important</h2>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">If you are used to always having control in your applications, you
- might not understand why all this life-cycle work is necessary. The reason
- is that in Android, you are not in control of your Activity, the
- operating system is!</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;
- padding:.0em .5em .5em 1em;">As we have already seen, the Android model is based around activities
- calling each other. When one Activity calls another, the current Activity
- is paused at the very least, and may be killed altogether if the
- system starts to run low on resources. If this happens, your Activity will
- have to store enough state to come back up later, preferably in the same
- state it was in when it was killed.</p>
- <p style="padding-left:.5em;font-size:12px;margin:0;padding:.0em .5em .5em 1em;">
- Android has a <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">well-defined life cycle</a>.
- Lifecycle events can happen even if you are not handing off control to
- another Activity explicitly. For example, perhaps a call comes in to the
- handset. If this happens, and your Activity is running, it will be swapped
- out while the call Activity takes over.</p>
- </div>
+ <div class="sidebox-wrapper">
+ <div class="sidebox">
+ <h2>Why handling life-cycle events is important</h2>
+ <p>If you are used to always having control in your applications, you
+ might not understand why all this life-cycle work is necessary. The reason
+ is that in Android, you are not in control of your Activity, the
+ operating system is!</p>
+ <p>As we have already seen, the Android model is based around activities
+ calling each other. When one Activity calls another, the current Activity
+ is paused at the very least, and may be killed altogether if the
+ system starts to run low on resources. If this happens, your Activity will
+ have to store enough state to come back up later, preferably in the same
+ state it was in when it was killed.</p>
+ <p>
+ Android has a <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">well-defined life
+cycle</a>.
+ Lifecycle events can happen even if you are not handing off control to
+ another Activity explicitly. For example, perhaps a call comes in to the
+ handset. If this happens, and your Activity is running, it will be swapped
+ out while the call Activity takes over.</p>
+ </div>
+ </div>
<p>Still in the <code>NoteEdit</code> class, we now override the methods
<code>onSaveInstanceState()</code>, <code>onPause()</code> and
diff --git a/docs/html/sdk/1.1_r1/upgrading.jd b/docs/html/sdk/1.1_r1/upgrading.jd
index 5628d04..bc71149 100644
--- a/docs/html/sdk/1.1_r1/upgrading.jd
+++ b/docs/html/sdk/1.1_r1/upgrading.jd
@@ -4,7 +4,7 @@
<!--
<div class="sidebox-wrapper">
- <div class="sidebox-inner">
+<div class="sidebox">
<h2>Useful Links</h2>
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index 698c347..7b98e7f 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -130,7 +130,7 @@
<h2 id="components">Add Android Platforms and Other Components</h2>
-<div class="sidebox-wrapper" style="margin-right:2.5em;">
+<div class="sidebox-wrapper">
<div class="sidebox">
<p>The <strong>Android SDK and AVD Manager</strong> tool is pre-installed in
your SDK. Using the tool is a key part of performing the initial setup of your
diff --git a/docs/html/sdk/win-usb.jd b/docs/html/sdk/win-usb.jd
index e0c2431..d3dce9e 100644
--- a/docs/html/sdk/win-usb.jd
+++ b/docs/html/sdk/win-usb.jd
@@ -50,7 +50,7 @@
<h2 id="WinUsbDriver">Installing the USB Driver for Windows</h2>
<div class="sidebox-wrapper">
-<div class="sidebox-inner">
+<div class="sidebox">
<p>The USB driver for Windows provides support for the following
Android-powered
devices:</p>
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 8dc206c..15d692c 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -63,13 +63,14 @@
import java.util.Date;
import java.util.Properties;
import java.util.Map.Entry;
+import java.util.concurrent.CountDownLatch;
/**
* A GPS implementation of LocationProvider used by LocationManager.
*
* {@hide}
*/
-public class GpsLocationProvider implements LocationProviderInterface, Runnable {
+public class GpsLocationProvider implements LocationProviderInterface {
private static final String TAG = "GpsLocationProvider";
@@ -190,7 +191,7 @@
private static final int NO_FIX_TIMEOUT = 60;
// true if we are enabled
- private boolean mEnabled;
+ private volatile boolean mEnabled;
// true if we have network connectivity
private boolean mNetworkAvailable;
@@ -236,7 +237,13 @@
private Bundle mLocationExtras = new Bundle();
private ArrayList<Listener> mListeners = new ArrayList<Listener>();
+ // GpsLocationProvider's handler thread
+ private final Thread mThread;
+ // Handler for processing events in mThread.
private Handler mHandler;
+ // Used to signal when our main thread has initialized everything
+ private final CountDownLatch mInitializedLatch = new CountDownLatch(1);
+ // Thread for receiving events from the native code
private Thread mEventThread;
private String mAGpsApn;
@@ -389,8 +396,17 @@
Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
}
- Thread thread = new Thread(null, this, "GpsLocationProvider");
- thread.start();
+ // wait until we are fully initialized before returning
+ mThread = new GpsLocationProviderThread();
+ mThread.start();
+ while (true) {
+ try {
+ mInitializedLatch.await();
+ break;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
}
private void initialize() {
@@ -673,7 +689,7 @@
}
private void handleDisable() {
- if (DEBUG) Log.d(TAG, "handleEnable");
+ if (DEBUG) Log.d(TAG, "handleDisable");
if (!mEnabled) return;
mEnabled = false;
@@ -1327,7 +1343,7 @@
// native_wait_for_event() will callback to us via reportLocation(), reportStatus(), etc.
// this is necessary because native code cannot call Java on a thread that the JVM does
// not know about.
- private class GpsEventThread extends Thread {
+ private final class GpsEventThread extends Thread {
public GpsEventThread() {
super("GpsEventThread");
@@ -1384,13 +1400,21 @@
}
};
- public void run()
- {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- initialize();
- Looper.prepare();
- mHandler = new ProviderHandler();
- Looper.loop();
+ private final class GpsLocationProviderThread extends Thread {
+
+ public GpsLocationProviderThread() {
+ super("GpsLocationProvider");
+ }
+
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ initialize();
+ Looper.prepare();
+ mHandler = new ProviderHandler();
+ // signal when we are initialized and ready to go
+ mInitializedLatch.countDown();
+ Looper.loop();
+ }
}
// for GPS SV statistics
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 407fd57..05e23d1 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1106,6 +1106,13 @@
mPreparedCondition.broadcast();
}
+// static
+bool AwesomePlayer::ContinuePreparation(void *cookie) {
+ AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie);
+
+ return (me->mFlags & PREPARE_CANCELLED) == 0;
+}
+
void AwesomePlayer::onPrepareAsyncEvent() {
sp<Prefetcher> prefetcher;
@@ -1161,10 +1168,22 @@
}
LOGI("calling prefetcher->prepare()");
- prefetcher->prepare();
- LOGV("prefetcher is done preparing");
+ status_t result =
+ prefetcher->prepare(&AwesomePlayer::ContinuePreparation, this);
prefetcher.clear();
+
+ if (result == OK) {
+ LOGV("prefetcher is done preparing");
+ } else {
+ Mutex::Autolock autoLock(mLock);
+
+ CHECK_EQ(result, -EINTR);
+
+ LOGI("prefetcher->prepare() was cancelled early.");
+ abortPrepare(UNKNOWN_ERROR);
+ return;
+ }
}
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9a092d5..20d9540 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -102,19 +102,26 @@
{ MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
+// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
+// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" },
+// { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
+// { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
+// { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
+// { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },
+// { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
};
static const CodecInfo kEncoderInfo[] = {
@@ -2962,6 +2969,16 @@
return OK;
}
+ if (strncmp(componentName, "OMX.", 4)) {
+ // Not an OpenMax component but a software codec.
+
+ results->push();
+ CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
+ caps->mComponentName = componentName;
+
+ continue;
+ }
+
sp<OMXCodecObserver> observer = new OMXCodecObserver;
IOMX::node_id node;
status_t err = omx->allocateNode(componentName, observer, &node);
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index debb60d..944a0c1 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -220,12 +220,19 @@
return minCacheDurationUs < 0 ? 0 : minCacheDurationUs;
}
-status_t Prefetcher::prepare() {
+status_t Prefetcher::prepare(
+ bool (*continueFunc)(void *cookie), void *cookie) {
// Fill the cache.
int64_t duration;
bool noMoreData;
do {
+ usleep(100000);
+
+ if (continueFunc && !(*continueFunc)(cookie)) {
+ return -EINTR;
+ }
+
duration = getCachedDurationUs(&noMoreData);
} while (!noMoreData && duration < 2000000ll);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 32c28c1..610f913 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -222,6 +222,8 @@
status_t finishSetDataSource_l();
+ static bool ContinuePreparation(void *cookie);
+
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
};
diff --git a/media/libstagefright/include/Prefetcher.h b/media/libstagefright/include/Prefetcher.h
index d227864..b411d1b 100644
--- a/media/libstagefright/include/Prefetcher.h
+++ b/media/libstagefright/include/Prefetcher.h
@@ -36,7 +36,12 @@
int64_t getCachedDurationUs(bool *noMoreData = NULL);
- status_t prepare();
+ // If provided (non-NULL), "continueFunc" will be called repeatedly
+ // while preparing and preparation will finish early if it returns
+ // false. In this case "-EINTR" is returned as a result.
+ status_t prepare(
+ bool (*continueFunc)(void *cookie) = NULL,
+ void *cookie = NULL);
protected:
virtual ~Prefetcher();
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 3f029a6..e07b3f9 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -159,6 +159,7 @@
private final static boolean LOG_SURFACE = false;
private final static boolean LOG_RENDERER = false;
private final static boolean LOG_RENDERER_DRAW_FRAME = false;
+ private final static boolean LOG_EGL = false;
// Work-around for bug 2263168
private final static boolean DRAW_TWICE_AFTER_SIZE_CHANGED = true;
/**
@@ -683,7 +684,14 @@
public void destroyContext(EGL10 egl, EGLDisplay display,
EGLContext context) {
- egl.eglDestroyContext(display, context);
+ if (!egl.eglDestroyContext(display, context)) {
+ Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+ if (LOG_THREADS) {
+ Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId());
+ }
+ throw new RuntimeException("eglDestroyContext failed: "
+ + EGLLogWrapper.getErrorString(egl.eglGetError()));
+ }
}
}
@@ -880,6 +888,9 @@
* @param configSpec
*/
public void start() {
+ if (LOG_EGL) {
+ Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
+ }
/*
* Get an EGL instance
*/
@@ -909,8 +920,12 @@
*/
mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
+ mEglContext = null;
throwEglException("createContext");
}
+ if (LOG_EGL) {
+ Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
+ }
mEglSurface = null;
}
@@ -920,6 +935,21 @@
* OpenGL interface that renders to that surface.
*/
public GL createSurface(SurfaceHolder holder) {
+ if (LOG_EGL) {
+ Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId());
+ }
+ /*
+ * Check preconditions.
+ */
+ if (mEgl == null) {
+ throw new RuntimeException("egl not initialized");
+ }
+ if (mEglDisplay == null) {
+ throw new RuntimeException("eglDisplay not initialized");
+ }
+ if (mEglConfig == null) {
+ throw new RuntimeException("mEglConfig not initialized");
+ }
/*
* The window size has changed, so we need to create a new
* surface.
@@ -942,6 +972,8 @@
mEglDisplay, mEglConfig, holder);
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+ Log.w("EglHelper", "createWindowSurface failed. mEglDisplay: " + mEglDisplay +
+ " mEglConfig: " + mEglConfig + " holder: " + holder);
throwEglException("createWindowSurface");
}
@@ -996,6 +1028,9 @@
}
public void destroySurface() {
+ if (LOG_EGL) {
+ Log.w("EglHelper", "destroySurface() tid=" + Thread.currentThread().getId());
+ }
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
@@ -1006,6 +1041,9 @@
}
public void finish() {
+ if (LOG_EGL) {
+ Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId());
+ }
if (mEglContext != null) {
mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
mEglContext = null;
@@ -1021,7 +1059,11 @@
}
private void throwEglException(String function, int error) {
- throw new RuntimeException(function + " failed: " + error);
+ String message = function + " failed: " + EGLLogWrapper.getErrorString(error);
+ if (LOG_THREADS) {
+ Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " " + message);
+ }
+ throw new RuntimeException(message);
}
EGL10 mEgl;
@@ -1137,6 +1179,12 @@
Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
}
}
+ if (sGLThreadManager.shouldTerminateEGLWhenPausing()) {
+ mEglHelper.finish();
+ if (LOG_SURFACE) {
+ Log.i("GLThread", "terminating EGL because paused tid=" + getId());
+ }
+ }
}
// Have we lost the surface view surface?
@@ -1174,9 +1222,14 @@
// If we don't have an EGL context, try to acquire one.
if ((! mHaveEglContext) && sGLThreadManager.tryAcquireEglContextLocked(this)) {
+ try {
+ mEglHelper.start();
+ } catch (RuntimeException t) {
+ sGLThreadManager.releaseEglContextLocked(this);
+ throw t;
+ }
mHaveEglContext = true;
createEglContext = true;
- mEglHelper.start();
sGLThreadManager.notifyAll();
}
@@ -1502,6 +1555,13 @@
}
public synchronized boolean shouldReleaseEGLContextWhenPausing() {
+ // Release the EGL context when pausing even if
+ // the hardware supports multiple EGL contexts.
+ // Otherwise the device could run out of EGL contexts.
+ return true;
+ }
+
+ public synchronized boolean shouldTerminateEGLWhenPausing() {
checkGLESVersion();
return !mMultipleGLESContextsAllowed;
}
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
index b38f1d2..0de11c6 100644
--- a/services/java/com/android/server/DropBoxManagerService.java
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -61,10 +61,11 @@
*/
public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
private static final String TAG = "DropBoxManagerService";
- private static final int DEFAULT_RESERVE_PERCENT = 10;
- private static final int DEFAULT_QUOTA_PERCENT = 10;
- private static final int DEFAULT_QUOTA_KB = 5 * 1024;
private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
+ private static final int DEFAULT_MAX_FILES = 1000;
+ private static final int DEFAULT_QUOTA_KB = 5 * 1024;
+ private static final int DEFAULT_QUOTA_PERCENT = 10;
+ private static final int DEFAULT_RESERVE_PERCENT = 10;
private static final int QUOTA_RESCAN_MILLIS = 5000;
private static final boolean PROFILE_DUMP = false;
@@ -99,12 +100,20 @@
@Override
public void onReceive(Context context, Intent intent) {
mCachedQuotaUptimeMillis = 0; // Force a re-check of quota size
- try {
- init();
- trimToFit();
- } catch (IOException e) {
- Slog.e(TAG, "Can't init", e);
- }
+
+ // Run the initialization in the background (not this main thread).
+ // The init() and trimToFit() methods are synchronized, so they still
+ // block other users -- but at least the onReceive() call can finish.
+ new Thread() {
+ public void run() {
+ try {
+ init();
+ trimToFit();
+ } catch (IOException e) {
+ Slog.e(TAG, "Can't init", e);
+ }
+ }
+ }.start();
}
};
@@ -631,10 +640,12 @@
int ageSeconds = Settings.Secure.getInt(mContentResolver,
Settings.Secure.DROPBOX_AGE_SECONDS, DEFAULT_AGE_SECONDS);
+ int maxFiles = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.DROPBOX_MAX_FILES, DEFAULT_MAX_FILES);
long cutoffMillis = System.currentTimeMillis() - ageSeconds * 1000;
while (!mAllFiles.contents.isEmpty()) {
EntryFile entry = mAllFiles.contents.first();
- if (entry.timestampMillis > cutoffMillis) break;
+ if (entry.timestampMillis > cutoffMillis && mAllFiles.contents.size() < maxFiles) break;
FileList tag = mFilesByTag.get(entry.tag);
if (tag != null && tag.contents.remove(entry)) tag.blocks -= entry.blocks;
@@ -673,7 +684,7 @@
// A single circular buffer (a la logcat) would be simpler, but this
// way we can handle fat/bursty data (like 1MB+ bugreports, 300KB+
// kernel crash dumps, and 100KB+ ANR reports) without swamping small,
- // well-behaved data // streams (event statistics, profile data, etc).
+ // well-behaved data streams (event statistics, profile data, etc).
//
// Deleted files are replaced with zero-length tombstones to mark what
// was lost. Tombstones are expunged by age (see above).
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 11020c2..1179500 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1394,9 +1394,18 @@
private boolean chooseNewDefaultIMELocked() {
List<InputMethodInfo> enabled = getEnabledInputMethodListLocked();
if (enabled != null && enabled.size() > 0) {
+ // We'd prefer to fall back on a system IME, since that is safer.
+ int i=enabled.size();
+ while (i > 0) {
+ i--;
+ if ((enabled.get(i).getServiceInfo().applicationInfo.flags
+ & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ break;
+ }
+ }
Settings.Secure.putString(mContext.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD,
- enabled.get(0).getId());
+ enabled.get(i).getId());
return true;
}
@@ -1435,7 +1444,7 @@
// System IMEs are enabled by default
if (isSystemIme(p)) {
- setInputMethodEnabled(p.getId(), true);
+ setInputMethodEnabledLocked(p.getId(), true);
}
if (DEBUG) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 53415c7..33a824b 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5214,8 +5214,19 @@
}
}
if (!PackageHelper.renameSdDir(cid, newCacheId)) {
- Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId);
- return false;
+ Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId +
+ " which might be stale. Will try to clean up.");
+ // Clean up the stale container and proceed to recreate.
+ if (!PackageHelper.destroySdDir(newCacheId)) {
+ Slog.e(TAG, "Very strange. Cannot clean up stale container " + newCacheId);
+ return false;
+ }
+ // Successfully cleaned up stale container. Try to rename again.
+ if (!PackageHelper.renameSdDir(cid, newCacheId)) {
+ Slog.e(TAG, "Failed to rename " + cid + " to " + newCacheId
+ + " inspite of cleaning it up.");
+ return false;
+ }
}
if (!PackageHelper.isContainerMounted(newCacheId)) {
Slog.w(TAG, "Mounting container " + newCacheId);
@@ -5258,7 +5269,7 @@
String sourceFile = getCodePath();
// Remove dex file
if (mInstaller != null) {
- int retCode = mInstaller.rmdex(sourceFile.toString());
+ int retCode = mInstaller.rmdex(sourceFile);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
+ " at location "
@@ -5613,7 +5624,7 @@
}
// Utility method used to move dex files during install.
- private int moveDexFiles(PackageParser.Package newPackage) {
+ private int moveDexFilesLI(PackageParser.Package newPackage) {
int retCode;
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath);
@@ -5636,7 +5647,7 @@
mSettings.writeLP();
}
- if ((res.returnCode = moveDexFiles(newPackage))
+ if ((res.returnCode = moveDexFilesLI(newPackage))
!= PackageManager.INSTALL_SUCCEEDED) {
// Discontinue if moving dex files failed.
return;
@@ -9568,6 +9579,9 @@
}
}
synchronized (mPackages) {
+ // Make sure group IDs have been assigned, and any permission
+ // changes in other apps are accounted for
+ updatePermissionsLP(null, null, true, false);
// Persist settings
mSettings.writeLP();
}
@@ -9697,41 +9711,43 @@
sendResourcesChangedBroadcast(false, pkgList, uidArr);
// Update package code and resource paths
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(mp.packageName);
- if (pkg != null) {
- String oldCodePath = pkg.mPath;
- String newCodePath = mp.targetArgs.getCodePath();
- String newResPath = mp.targetArgs.getResourcePath();
- pkg.mPath = newCodePath;
- // Move dex files around
- if (moveDexFiles(pkg)
- != PackageManager.INSTALL_SUCCEEDED) {
- // Moving of dex files failed. Set
- // error code and abort move.
- pkg.mPath = pkg.mScanPath;
- returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
- moveSucceeded = false;
- } else {
- pkg.mScanPath = newCodePath;
- pkg.applicationInfo.sourceDir = newCodePath;
- pkg.applicationInfo.publicSourceDir = newResPath;
- PackageSetting ps = (PackageSetting) pkg.mExtras;
- ps.codePath = new File(pkg.applicationInfo.sourceDir);
- ps.codePathString = ps.codePath.getPath();
- ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
- ps.resourcePathString = ps.resourcePath.getPath();
- // Set the application info flag correctly.
- if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ PackageParser.Package pkg = mPackages.get(mp.packageName);
+ if (pkg != null) {
+ String oldCodePath = pkg.mPath;
+ String newCodePath = mp.targetArgs.getCodePath();
+ String newResPath = mp.targetArgs.getResourcePath();
+ pkg.mPath = newCodePath;
+ // Move dex files around
+ if (moveDexFilesLI(pkg)
+ != PackageManager.INSTALL_SUCCEEDED) {
+ // Moving of dex files failed. Set
+ // error code and abort move.
+ pkg.mPath = pkg.mScanPath;
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ moveSucceeded = false;
} else {
- pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ pkg.mScanPath = newCodePath;
+ pkg.applicationInfo.sourceDir = newCodePath;
+ pkg.applicationInfo.publicSourceDir = newResPath;
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ ps.codePath = new File(pkg.applicationInfo.sourceDir);
+ ps.codePathString = ps.codePath.getPath();
+ ps.resourcePath = new File(pkg.applicationInfo.publicSourceDir);
+ ps.resourcePathString = ps.resourcePath.getPath();
+ // Set the application info flag correctly.
+ if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ } else {
+ pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+ }
+ ps.setFlags(pkg.applicationInfo.flags);
+ mAppDirs.remove(oldCodePath);
+ mAppDirs.put(newCodePath, pkg);
+ // Persist settings
+ mSettings.writeLP();
}
- ps.setFlags(pkg.applicationInfo.flags);
- mAppDirs.remove(oldCodePath);
- mAppDirs.put(newCodePath, pkg);
- // Persist settings
- mSettings.writeLP();
}
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 35b250e..b41443e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -232,18 +232,6 @@
PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
- mWifiStateTracker.setReleaseWakeLockCallback(
- new Runnable() {
- public void run() {
- mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK);
- synchronized (sDriverStopWakeLock) {
- if (sDriverStopWakeLock.isHeld()) {
- sDriverStopWakeLock.release();
- }
- }
- }
- }
- );
mContext.registerReceiver(
new BroadcastReceiver() {
@@ -433,12 +421,18 @@
return false;
}
- setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
-
+ /**
+ * Fail Wifi if AP is enabled
+ * TODO: Deprecate WIFI_STATE_UNKNOWN and rename it
+ * WIFI_STATE_FAILED
+ */
if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {
- setWifiApEnabledBlocking(false, Process.myUid(), null);
+ setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
+ return false;
}
+ setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);
+
if (enable) {
if (!mWifiStateTracker.loadDriver()) {
Slog.e(TAG, "Failed to load Wi-Fi driver.");
@@ -677,18 +671,19 @@
}
}
+ /**
+ * Fail AP if Wifi is enabled
+ */
+ if ((mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED) && enable) {
+ setWifiApEnabledState(WIFI_AP_STATE_FAILED, uid, DriverAction.NO_DRIVER_UNLOAD);
+ return false;
+ }
+
setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING :
WIFI_AP_STATE_DISABLING, uid, DriverAction.NO_DRIVER_UNLOAD);
if (enable) {
- /**
- * Disable client mode for starting AP
- */
- if (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED) {
- setWifiEnabledBlocking(false, true, Process.myUid());
- }
-
/* Use default config if there is no existing config */
if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) {
wifiConfig = new WifiConfiguration();
@@ -1779,20 +1774,16 @@
sendEnableMessage(true, false, mLastEnableUid);
sWakeLock.acquire();
sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
- } else {
+ } else if (!mWifiStateTracker.isDriverStopped()) {
int wakeLockTimeout =
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
DEFAULT_WAKELOCK_TIMEOUT);
/*
- * The following wakelock is held in order to ensure
- * that the connectivity manager has time to fail over
- * to the mobile data network. The connectivity manager
- * releases it once mobile data connectivity has been
- * established. If connectivity cannot be established,
- * the wakelock is released after wakeLockTimeout
- * milliseconds have elapsed.
+ * We are assuming that ConnectivityService can make
+ * a transition to cellular data within wakeLockTimeout time.
+ * The wakelock is released by the delayed message.
*/
sDriverStopWakeLock.acquire();
mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
@@ -1886,11 +1877,7 @@
break;
case MESSAGE_RELEASE_WAKELOCK:
- synchronized (sDriverStopWakeLock) {
- if (sDriverStopWakeLock.isHeld()) {
- sDriverStopWakeLock.release();
- }
- }
+ sDriverStopWakeLock.release();
break;
case MESSAGE_START_ACCESS_POINT:
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f734053..d1edc35 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -69,6 +69,7 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -122,6 +123,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
static final String TAG = "ActivityManager";
@@ -9352,6 +9354,32 @@
return runList;
}
+ public List<ApplicationInfo> getRunningExternalApplications() {
+ List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
+ List<ApplicationInfo> retList = new ArrayList<ApplicationInfo>();
+ if (runningApps != null && runningApps.size() > 0) {
+ Set<String> extList = new HashSet<String>();
+ for (ActivityManager.RunningAppProcessInfo app : runningApps) {
+ if (app.pkgList != null) {
+ for (String pkg : app.pkgList) {
+ extList.add(pkg);
+ }
+ }
+ }
+ IPackageManager pm = ActivityThread.getPackageManager();
+ for (String pkg : extList) {
+ try {
+ ApplicationInfo info = pm.getApplicationInfo(pkg, 0);
+ if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ retList.add(info);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ return retList;
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (checkCallingPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/status/UsbStorageActivity.java b/services/java/com/android/server/status/UsbStorageActivity.java
index b3ee257..e8631c53 100644
--- a/services/java/com/android/server/status/UsbStorageActivity.java
+++ b/services/java/com/android/server/status/UsbStorageActivity.java
@@ -18,6 +18,7 @@
import com.android.internal.R;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
@@ -26,6 +27,9 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.DialogInterface.OnCancelListener;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -43,6 +47,8 @@
import android.view.Window;
import android.util.Log;
+import java.util.List;
+
/**
* This activity is shown to the user for him/her to enable USB mass storage
* on-demand (that is, when the USB cable is connected). It uses the alert
@@ -175,7 +181,7 @@
.setTitle(R.string.dlg_confirm_kill_storage_users_title)
.setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
- mStorageManager.enableUsbMassStorage();
+ switchUsbMassStorageAsync(true);
}})
.setNegativeButton(R.string.cancel, null)
.setMessage(R.string.dlg_confirm_kill_storage_users_text)
@@ -222,15 +228,25 @@
// Display error dialog
showDialogInner(DLG_ERROR_SHARING);
}
- String path = Environment.getExternalStorageDirectory().getPath();
- int stUsers[] = null;
+ String extStoragePath = Environment.getExternalStorageDirectory().toString();
+ boolean showDialog = false;
try {
- if (localLOGV) Log.i(TAG, "Checking getStorageUsers");
- stUsers = ims.getStorageUsers(path);
+ int[] stUsers = ims.getStorageUsers(extStoragePath);
+ if (stUsers != null && stUsers.length > 0) {
+ showDialog = true;
+ } else {
+ // List of applications on sdcard.
+ ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+ List<ApplicationInfo> infoList = am.getRunningExternalApplications();
+ if (infoList != null && infoList.size() > 0) {
+ showDialog = true;
+ }
+ }
} catch (RemoteException e) {
+ // Display error dialog
showDialogInner(DLG_ERROR_SHARING);
}
- if (stUsers != null && stUsers.length > 0) {
+ if (showDialog) {
// Display dialog to user
showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS);
} else {
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
index 3842d45..78a90fb 100644
--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -39,6 +39,7 @@
public void tearDown() throws Exception {
ContentResolver cr = getContext().getContentResolver();
Settings.Secure.putString(cr, Settings.Secure.DROPBOX_AGE_SECONDS, "");
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_MAX_FILES, "");
Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, "");
Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
}
@@ -457,6 +458,55 @@
e0.close();
}
+ public void testFileCountLimits() throws Exception {
+ File dir = getEmptyDir("testFileCountLimits");
+
+ DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+ DropBoxManager dropbox = new DropBoxManager(service);
+ dropbox.addText("DropBoxTest", "TEST0");
+ dropbox.addText("DropBoxTest", "TEST1");
+ dropbox.addText("DropBoxTest", "TEST2");
+ dropbox.addText("DropBoxTest", "TEST3");
+ dropbox.addText("DropBoxTest", "TEST4");
+ dropbox.addText("DropBoxTest", "TEST5");
+
+ // Verify 6 files added
+ DropBoxManager.Entry e0 = dropbox.getNextEntry(null, 0);
+ DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+ DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
+ DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
+ DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
+ DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, e5.getTimeMillis()));
+ assertEquals("TEST0", e0.getText(80));
+ assertEquals("TEST5", e5.getText(80));
+
+ e0.close();
+ e1.close();
+ e2.close();
+ e3.close();
+ e4.close();
+ e5.close();
+
+ // Limit to 3 files and add one more entry
+ ContentResolver cr = getContext().getContentResolver();
+ Settings.Secure.putString(cr, Settings.Secure.DROPBOX_MAX_FILES, "3");
+ dropbox.addText("DropBoxTest", "TEST6");
+
+ // Verify only 3 files left
+ DropBoxManager.Entry f0 = dropbox.getNextEntry(null, 0);
+ DropBoxManager.Entry f1 = dropbox.getNextEntry(null, f0.getTimeMillis());
+ DropBoxManager.Entry f2 = dropbox.getNextEntry(null, f1.getTimeMillis());
+ assertTrue(null == dropbox.getNextEntry(null, f2.getTimeMillis()));
+ assertEquals("TEST4", f0.getText(80));
+ assertEquals("TEST5", f1.getText(80));
+ assertEquals("TEST6", f2.getText(80));
+
+ f0.close();
+ f1.close();
+ f2.close();
+ }
+
public void testCreateDropBoxManagerWithInvalidDirectory() throws Exception {
// If created with an invalid directory, the DropBoxManager should suffer quietly
// and fail all operations (this is how it survives a full disk).
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 6975c70..449661c 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -520,24 +520,6 @@
}
}
}
-
- public void clearSecureContainersForPkg(String pkgName) {
- IMountService ms = getMs();
- try {
- String list[] = ms.getSecureContainerList();
- if (list != null) {
- for (String cid : list) {
- boolean delete = false;
- // STOPSHIP issues with rename should be fixed.
- if (cid.contains(pkgName) ||
- cid.contains("smdltmp")) {
- Log.i(TAG, "Destroying container " + cid);
- ms.destroySecureContainer(cid, true);
- }
- }
- }
- } catch (RemoteException e) {}
- }
/*
* Utility function that reads a apk bundled as a raw resource
@@ -792,7 +774,7 @@
waitTime += WAIT_TIME_INCR;
}
if(!receiver.isDone()) {
- throw new Exception("Timed out waiting for PACKAGE_ADDED notification");
+ throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
}
return receiver.received;
}
@@ -2186,6 +2168,49 @@
}
}
}
+
+ /* This test creates a stale container via MountService and then installs
+ * a package and verifies that the stale container is cleaned up and install
+ * is successful.
+ * Please note that this test is very closely tied to the framework's
+ * naming convention for secure containers.
+ */
+ public void testInstallSdcardStaleContainer() {
+ boolean origMediaState = getMediaState();
+ try {
+ String outFileName = "install.apk";
+ int rawResId = R.raw.install;
+ PackageManager pm = mContext.getPackageManager();
+ File filesDir = mContext.getFilesDir();
+ File outFile = new File(filesDir, outFileName);
+ Uri packageURI = getInstallablePackage(rawResId, outFile);
+ PackageParser.Package pkg = parsePackage(packageURI);
+ assertNotNull(pkg);
+ // Install an app on sdcard.
+ installFromRawResource(outFileName, rawResId,
+ PackageManager.INSTALL_EXTERNAL, false,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ // Unmount sdcard
+ unmountMedia();
+ // Delete the app on sdcard to leave a stale container on sdcard.
+ GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
+ assertTrue(invokeDeletePackage(packageURI, 0, pkg.packageName, receiver));
+ mountMedia();
+ // Reinstall the app and make sure it gets installed.
+ installFromRawResource(outFileName, rawResId,
+ PackageManager.INSTALL_EXTERNAL, true,
+ false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ } catch (Exception e) {
+ failStr(e.getMessage());
+ } finally {
+ if (origMediaState) {
+ mountMedia();
+ } else {
+ unmountMedia();
+ }
+
+ }
+ }
/*---------- Recommended install location tests ----*/
/*
* TODO's
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index c8b6837..3308a35 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -162,10 +162,11 @@
void setPackageCount(int val) { mPackageCount = val; }
#endif
- /* UTF-8 is only available on APIs 7 or above or
- * SDK levels that have code names.
+ /* Certain features may only be available on a specific SDK level or
+ * above. SDK levels that have a non-numeric identifier are assumed
+ * to be newer than any SDK level that has a number designated.
*/
- bool isUTF8Available() {
+ bool isMinSdkAtLeast(int desired) {
/* If the application specifies a minSdkVersion in the manifest
* then use that. Otherwise, check what the user specified on
* the command line. If neither, it's not available since
@@ -183,7 +184,7 @@
char *end;
int minSdkNum = (int)strtol(minVer, &end, 0);
if (*end == '\0') {
- if (minSdkNum < 7) {
+ if (minSdkNum < desired) {
return false;
}
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index a8ac2ec..cafd635 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -775,7 +775,7 @@
* allow UTF-8 to be used.
*/
if (!bundle->getWantUTF16()
- && bundle->isUTF8Available()) {
+ && bundle->isMinSdkAtLeast(SDK_FROYO)) {
xmlFlags |= XML_COMPILE_UTF8;
}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 66db450..a2f085a 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2527,7 +2527,7 @@
const size_t N = mOrderedPackages.size();
size_t pi;
- bool useUTF8 = !bundle->getWantUTF16() && bundle->isUTF8Available();
+ bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO);
// Iterate through all data, collecting all values (strings,
// references, etc).
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 80b8aedfa..4f84aab 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -313,8 +313,6 @@
private String mInterfaceName;
private static String LS = System.getProperty("line.separator");
- private Runnable mReleaseWakeLockCallback;
-
private static String[] sDnsPropNames;
/**
@@ -615,7 +613,15 @@
}
}
- private synchronized boolean isDriverStopped() {
+ /**
+ * TODO: mRunState is not synchronized in some places
+ * address this as part of re-architect.
+ *
+ * TODO: We are exposing an additional public synchronized call
+ * for a wakelock optimization in WifiService. Remove it
+ * when we handle the wakelock in ConnectivityService.
+ */
+ public synchronized boolean isDriverStopped() {
return mRunState == RUN_STATE_STOPPED || mRunState == RUN_STATE_STOPPING;
}
@@ -674,15 +680,20 @@
}
}
+ /**
+ * We release the wakelock in WifiService
+ * using a timer.
+ *
+ * TODO:
+ * Releasing wakelock using both timer and
+ * a call from ConnectivityService requires
+ * a rethink. We had problems where WifiService
+ * could keep a wakelock forever if we delete
+ * messages in the asynchronous call
+ * from ConnectivityService
+ */
@Override
public void releaseWakeLock() {
- if (mReleaseWakeLockCallback != null) {
- mReleaseWakeLockCallback.run();
- }
- }
-
- public void setReleaseWakeLockCallback(Runnable callback) {
- mReleaseWakeLockCallback = callback;
}
/**
@@ -1481,20 +1492,6 @@
} else {
return disconnect();
}
- } else {
- /*
- * The "driver-stop" wake lock normally is released from the
- * connectivity manager after the mobile data connection has
- * been established, or after a timeout period, if that never
- * happens. Because WifiService.updateWifiState() can get called
- * multiple times, we can end up acquiring the wake lock and calling
- * disconnectAndStop() even when a disconnect or stop operation
- * is already in progress. In that case, we want to ignore the
- * disconnectAndStop request and release the (ref-counted) wake
- * lock, so that eventually, when the mobile data connection is
- * established, the ref count will drop to zero.
- */
- releaseWakeLock();
}
return true;
}