Merge "Import revised translations."
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 91def67..1ba8eee 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1033,8 +1033,12 @@
mContext.getString(R.string.permission_request_notification_with_subtitle,
account.name);
final int index = titleAndSubtitle.indexOf('\n');
- final String title = titleAndSubtitle.substring(0, index);
- final String subtitle = titleAndSubtitle.substring(index + 1);
+ String title = titleAndSubtitle;
+ String subtitle = "";
+ if (index > 0) {
+ title = titleAndSubtitle.substring(0, index);
+ subtitle = titleAndSubtitle.substring(index + 1);
+ }
n.setLatestEventInfo(mContext,
title, subtitle,
PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 0c034cf..170171e 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -35,7 +35,7 @@
*/
public class WallpaperBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "WallpaperBackupHelper";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
// This path must match what the WallpaperManagerService uses
private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 6228bd0..7af535b 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -19,6 +19,7 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.AsyncTask;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 5fe42db..3f23b89 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -64,7 +64,10 @@
/* Methods that may optionally be implemented by subclasses */
/**
- * returns a pre-filled window, return NULL if no such window
+ * If the cursor is backed by a {@link CursorWindow}, returns a pre-filled
+ * window with the contents of the cursor, otherwise null.
+ *
+ * @return The pre-filled window that backs this cursor, or null if none.
*/
public CursorWindow getWindow() {
return null;
diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java
index 3d95769..bfc8123 100644
--- a/core/java/android/database/AbstractWindowedCursor.java
+++ b/core/java/android/database/AbstractWindowedCursor.java
@@ -18,8 +18,22 @@
/**
* A base class for Cursors that store their data in {@link CursorWindow}s.
+ * <p>
+ * Subclasses are responsible for filling the cursor window with data during
+ * {@link #onMove(int, int)}, allocating a new cursor window if necessary.
+ * During {@link #requery()}, the existing cursor window should be cleared and
+ * filled with new data.
+ * </p><p>
+ * If the contents of the cursor change or become invalid, the old window must be closed
+ * (because it is owned by the cursor) and set to null.
+ * </p>
*/
public abstract class AbstractWindowedCursor extends AbstractCursor {
+ /**
+ * The cursor window owned by this cursor.
+ */
+ protected CursorWindow mWindow;
+
@Override
public byte[] getBlob(int columnIndex) {
checkPosition();
@@ -126,25 +140,44 @@
public CursorWindow getWindow() {
return mWindow;
}
-
+
/**
- * Set a new cursor window to cursor, usually set a remote cursor window
- * @param window cursor window
+ * Sets a new cursor window for the cursor to use.
+ * <p>
+ * The cursor takes ownership of the provided cursor window; the cursor window
+ * will be closed when the cursor is closed or when the cursor adopts a new
+ * cursor window.
+ * </p><p>
+ * If the cursor previously had a cursor window, then it is closed when the
+ * new cursor window is assigned.
+ * </p>
+ *
+ * @param window The new cursor window, typically a remote cursor window.
*/
public void setWindow(CursorWindow window) {
- if (mWindow != null) {
- mWindow.close();
+ if (window != mWindow) {
+ closeWindow();
+ mWindow = window;
}
- mWindow = window;
}
-
+
+ /**
+ * Returns true if the cursor has an associated cursor window.
+ *
+ * @return True if the cursor has an associated cursor window.
+ */
public boolean hasWindow() {
return mWindow != null;
}
/**
- * This needs be updated in {@link #onMove} by subclasses, and
- * needs to be set to NULL when the contents of the cursor change.
+ * Closes the cursor window and sets {@link #mWindow} to null.
+ * @hide
*/
- protected CursorWindow mWindow;
+ protected void closeWindow() {
+ if (mWindow != null) {
+ mWindow.close();
+ mWindow = null;
+ }
+ }
}
diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java
index 16becf5..9c1b26d 100644
--- a/core/java/android/database/BulkCursorToCursorAdaptor.java
+++ b/core/java/android/database/BulkCursorToCursorAdaptor.java
@@ -154,10 +154,7 @@
false /* the window will be accessed across processes */));
if (mCount != -1) {
mPos = -1;
- if (mWindow != null) {
- mWindow.close();
- mWindow = null;
- }
+ closeWindow();
// super.requery() will call onChanged. Do it here instead of relying on the
// observer from the far side so that observers can see a correct value for mCount
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 183662f..2e3ef28 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -105,8 +105,12 @@
}
@Override
- protected void finalize() {
- dispose();
+ protected void finalize() throws Throwable {
+ try {
+ dispose();
+ } finally {
+ super.finalize();
+ }
}
private void dispose() {
@@ -145,10 +149,12 @@
/**
* Gets the start position of this cursor window.
- * The start position is the index of the first row that this window contains
+ * <p>
+ * The start position is the zero-based index of the first row that this window contains
* relative to the entire result set of the {@link Cursor}.
+ * </p>
*
- * @return The start position.
+ * @return The zero-based start position.
*/
public int getStartPosition() {
return mStartPos;
@@ -156,10 +162,12 @@
/**
* Sets the start position of this cursor window.
- * The start position is the index of the first row that this window contains
+ * <p>
+ * The start position is the zero-based index of the first row that this window contains
* relative to the entire result set of the {@link Cursor}.
+ * </p>
*
- * @param pos The new start position.
+ * @param pos The new zero-based start position.
*/
public void setStartPosition(int pos) {
mStartPos = pos;
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index 3c3bd43..320733e 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -33,7 +33,9 @@
}
/**
- * @return the wrapped cursor
+ * Gets the underlying cursor that is wrapped by this instance.
+ *
+ * @return The wrapped cursor.
*/
public Cursor getWrappedCursor() {
return mCursor;
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index ea9346d..81fe824 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -18,16 +18,11 @@
import android.database.AbstractWindowedCursor;
import android.database.CursorWindow;
-import android.database.DataSetObserver;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Process;
import android.os.StrictMode;
import android.util.Log;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.locks.ReentrantLock;
/**
* A Cursor implementation that exposes results from a query on a
@@ -60,140 +55,8 @@
/** Used to find out where a cursor was allocated in case it never got released. */
private final Throwable mStackTrace;
-
- /**
- * mMaxRead is the max items that each cursor window reads
- * default to a very high value
- */
- private int mMaxRead = Integer.MAX_VALUE;
- private int mInitialRead = Integer.MAX_VALUE;
- private int mCursorState = 0;
- private ReentrantLock mLock = null;
- private boolean mPendingData = false;
/**
- * support for a cursor variant that doesn't always read all results
- * initialRead is the initial number of items that cursor window reads
- * if query contains more than this number of items, a thread will be
- * created and handle the left over items so that caller can show
- * results as soon as possible
- * @param initialRead initial number of items that cursor read
- * @param maxRead leftover items read at maxRead items per time
- * @hide
- */
- public void setLoadStyle(int initialRead, int maxRead) {
- mMaxRead = maxRead;
- mInitialRead = initialRead;
- mLock = new ReentrantLock(true);
- }
-
- private void queryThreadLock() {
- if (mLock != null) {
- mLock.lock();
- }
- }
-
- private void queryThreadUnlock() {
- if (mLock != null) {
- mLock.unlock();
- }
- }
-
-
- /**
- * @hide
- */
- final private class QueryThread implements Runnable {
- private final int mThreadState;
- QueryThread(int version) {
- mThreadState = version;
- }
- private void sendMessage() {
- if (mNotificationHandler != null) {
- mNotificationHandler.sendEmptyMessage(1);
- mPendingData = false;
- } else {
- mPendingData = true;
- }
-
- }
- public void run() {
- // use cached mWindow, to avoid get null mWindow
- CursorWindow cw = mWindow;
- Process.setThreadPriority(Process.myTid(), Process.THREAD_PRIORITY_BACKGROUND);
- // the cursor's state doesn't change
- while (true) {
- mLock.lock();
- try {
- if (mCursorState != mThreadState) {
- break;
- }
-
- int count = getQuery().fillWindow(cw, mMaxRead, mCount);
- // return -1 means there is still more data to be retrieved from the resultset
- if (count != 0) {
- if (count == NO_COUNT){
- mCount += mMaxRead;
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "received -1 from native_fill_window. read " +
- mCount + " rows so far");
- }
- sendMessage();
- } else {
- mCount += count;
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "received all data from native_fill_window. read " +
- mCount + " rows.");
- }
- sendMessage();
- break;
- }
- } else {
- break;
- }
- } catch (Exception e) {
- // end the tread when the cursor is close
- break;
- } finally {
- mLock.unlock();
- }
- }
- }
- }
-
- /**
- * @hide
- */
- protected class MainThreadNotificationHandler extends Handler {
- public void handleMessage(Message msg) {
- notifyDataSetChange();
- }
- }
-
- /**
- * @hide
- */
- protected MainThreadNotificationHandler mNotificationHandler;
-
- public void registerDataSetObserver(DataSetObserver observer) {
- super.registerDataSetObserver(observer);
- if ((Integer.MAX_VALUE != mMaxRead || Integer.MAX_VALUE != mInitialRead) &&
- mNotificationHandler == null) {
- queryThreadLock();
- try {
- mNotificationHandler = new MainThreadNotificationHandler();
- if (mPendingData) {
- notifyDataSetChange();
- mPendingData = false;
- }
- } finally {
- queryThreadUnlock();
- }
- }
-
- }
-
- /**
* Execute a query and provide access to its result set through a Cursor
* interface. For a query such as: {@code SELECT name, birth, phone FROM
* myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
@@ -293,36 +156,23 @@
return mCount;
}
- private void fillWindow (int startPos) {
+ private void fillWindow(int startPos) {
if (mWindow == null) {
// If there isn't a window set already it will only be accessed locally
mWindow = new CursorWindow(true /* the window is local only */);
} else {
- mCursorState++;
- queryThreadLock();
- try {
- mWindow.clear();
- } finally {
- queryThreadUnlock();
- }
+ mWindow.clear();
}
mWindow.setStartPosition(startPos);
- int count = getQuery().fillWindow(mWindow, mInitialRead, 0);
- // return -1 means there is still more data to be retrieved from the resultset
- if (count == NO_COUNT){
- mCount = startPos + mInitialRead;
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "received -1 from native_fill_window. read " + mCount + " rows so far");
- }
- Thread t = new Thread(new QueryThread(mCursorState), "query thread");
- t.start();
- } else if (startPos == 0) { // native_fill_window returns count(*) only for startPos = 0
+ int count = getQuery().fillWindow(mWindow);
+ if (startPos == 0) { // fillWindow returns count(*) only for startPos = 0
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "received count(*) from native_fill_window: " + count);
}
mCount = count;
} else if (mCount <= 0) {
- throw new IllegalStateException("count should never be non-zero negative number");
+ throw new IllegalStateException("Row count should never be zero or negative "
+ + "when the start position is non-zero");
}
}
@@ -366,11 +216,7 @@
private void deactivateCommon() {
if (false) Log.v(TAG, "<<< Releasing cursor " + this);
- mCursorState = 0;
- if (mWindow != null) {
- mWindow.close();
- mWindow = null;
- }
+ closeWindow();
if (false) Log.v("DatabaseWindow", "closing window in release()");
}
@@ -439,16 +285,12 @@
// This one will recreate the temp table, and get its count
mDriver.cursorRequeried(this);
mCount = NO_COUNT;
- mCursorState++;
- queryThreadLock();
try {
mQuery.requery();
} catch (IllegalStateException e) {
// for backwards compatibility, just return false
Log.w(TAG, "requery() failed " + e.getMessage(), e);
return false;
- } finally {
- queryThreadUnlock();
}
}
@@ -472,18 +314,9 @@
}
@Override
- public void setWindow(CursorWindow window) {
- if (mWindow != null) {
- mCursorState++;
- queryThreadLock();
- try {
- mWindow.close();
- } finally {
- queryThreadUnlock();
- }
- mCount = NO_COUNT;
- }
- mWindow = window;
+ public void setWindow(CursorWindow window) {
+ super.setWindow(window);
+ mCount = NO_COUNT;
}
/**
@@ -521,11 +354,4 @@
super.finalize();
}
}
-
- /**
- * this is only for testing purposes.
- */
- /* package */ int getMCount() {
- return mCount;
- }
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index d23873d..00d7ce8 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1598,32 +1598,6 @@
}
/**
- * Runs the provided SQL and returns a cursor over the result set.
- * The cursor will read an initial set of rows and the return to the caller.
- * It will continue to read in batches and send data changed notifications
- * when the later batches are ready.
- * @param sql the SQL query. The SQL string must not be ; terminated
- * @param selectionArgs You may include ?s in where clause in the query,
- * which will be replaced by the values from selectionArgs. The
- * values will be bound as Strings.
- * @param initialRead set the initial count of items to read from the cursor
- * @param maxRead set the count of items to read on each iteration after the first
- * @return A {@link Cursor} object, which is positioned before the first entry. Note that
- * {@link Cursor}s are not synchronized, see the documentation for more details.
- *
- * This work is incomplete and not fully tested or reviewed, so currently
- * hidden.
- * @hide
- */
- public Cursor rawQuery(String sql, String[] selectionArgs,
- int initialRead, int maxRead) {
- SQLiteCursor c = (SQLiteCursor)rawQueryWithFactory(
- null, sql, selectionArgs, null);
- c.setLoadStyle(initialRead, maxRead);
- return c;
- }
-
- /**
* Convenience method for inserting a row into the database.
*
* @param table the table to insert the row into
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 06a41b2..7db0914 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -30,6 +30,11 @@
public class SQLiteQuery extends SQLiteProgram {
private static final String TAG = "SQLiteQuery";
+ private static native int nativeFillWindow(int databasePtr, int statementPtr, int windowPtr,
+ int startPos, int offsetParam);
+ private static native int nativeColumnCount(int statementPtr);
+ private static native String nativeColumnName(int statementPtr, int columnIndex);
+
/** The index of the unbound OFFSET parameter */
private int mOffsetIndex = 0;
@@ -68,19 +73,15 @@
* @param window The window to fill into
* @return number of total rows in the query
*/
- /* package */ int fillWindow(CursorWindow window,
- int maxRead, int lastPos) {
+ /* package */ int fillWindow(CursorWindow window) {
mDatabase.lock(mSql);
long timeStart = SystemClock.uptimeMillis();
try {
acquireReference();
try {
window.acquireReference();
- // 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.mWindowPtr, window.getStartPosition(),
- mOffsetIndex, maxRead, lastPos);
+ int numRows = nativeFillWindow(nHandle, nStatement, window.mWindowPtr,
+ window.getStartPosition(), mOffsetIndex);
mDatabase.logTimeStat(mSql, timeStart);
return numRows;
} catch (IllegalStateException e){
@@ -111,7 +112,7 @@
/* package */ int columnCountLocked() {
acquireReference();
try {
- return native_column_count();
+ return nativeColumnCount(nStatement);
} finally {
releaseReference();
}
@@ -127,17 +128,17 @@
/* package */ String columnNameLocked(int columnIndex) {
acquireReference();
try {
- return native_column_name(columnIndex);
+ return nativeColumnName(nStatement, columnIndex);
} finally {
releaseReference();
}
}
-
+
@Override
public String toString() {
return "SQLiteQuery: " + mSql;
}
-
+
@Override
public void close() {
super.close();
@@ -153,11 +154,4 @@
}
compileAndbindAllArgs();
}
-
- private final native int native_fill_window(int windowPtr,
- int startPos, int offsetParam, int maxRead, int lastPos);
-
- private final native int native_column_count();
-
- private final native String native_column_name(int columnIndex);
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index e554975..69ac1e7 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -229,6 +229,14 @@
return elapsedRealtime;
}
+ /**
+ * Return age of this {@link NetworkStats} object with respect to
+ * {@link SystemClock#elapsedRealtime()}.
+ */
+ public long getElapsedRealtimeAge() {
+ return SystemClock.elapsedRealtime() - elapsedRealtime;
+ }
+
public int size() {
return size;
}
@@ -354,26 +362,59 @@
* Return total of all fields represented by this snapshot object.
*/
public Entry getTotal(Entry recycle) {
+ return getTotal(recycle, null, UID_ALL);
+ }
+
+ /**
+ * Return total of all fields represented by this snapshot object matching
+ * the requested {@link #uid}.
+ */
+ public Entry getTotal(Entry recycle, int limitUid) {
+ return getTotal(recycle, null, limitUid);
+ }
+
+ /**
+ * Return total of all fields represented by this snapshot object matching
+ * the requested {@link #iface}.
+ */
+ public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
+ return getTotal(recycle, limitIface, UID_ALL);
+ }
+
+ /**
+ * Return total of all fields represented by this snapshot object matching
+ * the requested {@link #iface} and {@link #uid}.
+ *
+ * @param limitIface Set of {@link #iface} to include in total; or {@code
+ * null} to include all ifaces.
+ */
+ private Entry getTotal(Entry recycle, HashSet<String> limitIface, int limitUid) {
final Entry entry = recycle != null ? recycle : new Entry();
entry.iface = IFACE_ALL;
- entry.uid = UID_ALL;
+ entry.uid = limitUid;
entry.set = SET_ALL;
entry.tag = TAG_NONE;
entry.rxBytes = 0;
entry.rxPackets = 0;
entry.txBytes = 0;
entry.txPackets = 0;
+ entry.operations = 0;
for (int i = 0; i < size; i++) {
- // skip specific tags, since already counted in TAG_NONE
- if (tag[i] != TAG_NONE) continue;
+ final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]);
+ final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i]));
- entry.rxBytes += rxBytes[i];
- entry.rxPackets += rxPackets[i];
- entry.txBytes += txBytes[i];
- entry.txPackets += txPackets[i];
- entry.operations += operations[i];
+ if (matchesUid && matchesIface) {
+ // skip specific tags, since already counted in TAG_NONE
+ if (tag[i] != TAG_NONE) continue;
+
+ entry.rxBytes += rxBytes[i];
+ entry.rxPackets += rxPackets[i];
+ entry.txBytes += txBytes[i];
+ entry.txPackets += txPackets[i];
+ entry.operations += operations[i];
+ }
}
return entry;
}
@@ -495,6 +536,34 @@
return stats;
}
+ /**
+ * Return total statistics grouped by {@link #uid}; doesn't mutate the
+ * original structure.
+ */
+ public NetworkStats groupedByUid() {
+ final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
+
+ final Entry entry = new Entry();
+ entry.iface = IFACE_ALL;
+ entry.set = SET_ALL;
+ entry.tag = TAG_NONE;
+
+ for (int i = 0; i < size; i++) {
+ // skip specific tags, since already counted in TAG_NONE
+ if (tag[i] != TAG_NONE) continue;
+
+ entry.uid = uid[i];
+ entry.rxBytes = rxBytes[i];
+ entry.rxPackets = rxPackets[i];
+ entry.txBytes = txBytes[i];
+ entry.txPackets = txPackets[i];
+ entry.operations = operations[i];
+ stats.combineValues(entry);
+ }
+
+ return stats;
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 2961fd2..5e93b81 100644
--- a/core/java/android/server/BluetoothHealthProfileHandler.java
+++ b/core/java/android/server/BluetoothHealthProfileHandler.java
@@ -45,8 +45,7 @@
*/
final class BluetoothHealthProfileHandler {
private static final String TAG = "BluetoothHealthProfileHandler";
- /*STOPSHIP*/
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
private static BluetoothHealthProfileHandler sInstance;
private BluetoothService mBluetoothService;
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 1379dd2d..6e95016 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -56,6 +56,14 @@
*/
public static final int FLAG_MISSPELLED = 0x0002;
+ /**
+ * Sets this flag if the auto correction is about to be applied to a word/text
+ * that the user is typing/composing. This type of suggestion is rendered differently
+ * to indicate the auto correction is happening.
+ * @hide
+ */
+ public static final int FLAG_AUTO_CORRECTION = 0x0004;
+
public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before";
@@ -82,6 +90,9 @@
private float mMisspelledUnderlineThickness;
private int mMisspelledUnderlineColor;
+ private float mAutoCorrectionUnderlineThickness;
+ private int mAutoCorrectionUnderlineColor;
+
/*
* TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
* and InputMethodSubtype.
@@ -145,14 +156,21 @@
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
-
typedArray = context.obtainStyledAttributes(
null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
-
mEasyCorrectUnderlineThickness = typedArray.getDimension(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
mEasyCorrectUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+
+ defStyle = com.android.internal.R.attr.textAppearanceAutoCorrectionSuggestion;
+ typedArray = context.obtainStyledAttributes(
+ null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0);
+ mAutoCorrectionUnderlineThickness = typedArray.getDimension(
+ com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
+ mAutoCorrectionUnderlineColor = typedArray.getColor(
+ com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+
}
public SuggestionSpan(Parcel src) {
@@ -165,6 +183,8 @@
mEasyCorrectUnderlineThickness = src.readFloat();
mMisspelledUnderlineColor = src.readInt();
mMisspelledUnderlineThickness = src.readFloat();
+ mAutoCorrectionUnderlineColor = src.readInt();
+ mAutoCorrectionUnderlineThickness = src.readFloat();
}
/**
@@ -218,6 +238,8 @@
dest.writeFloat(mEasyCorrectUnderlineThickness);
dest.writeInt(mMisspelledUnderlineColor);
dest.writeFloat(mMisspelledUnderlineThickness);
+ dest.writeInt(mAutoCorrectionUnderlineColor);
+ dest.writeFloat(mAutoCorrectionUnderlineThickness);
}
@Override
@@ -261,6 +283,7 @@
public void updateDrawState(TextPaint tp) {
final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+ final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0;
if (easy) {
if (!misspelled) {
tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
@@ -269,6 +292,8 @@
// than just easy, do not apply misspelled if an easy (or a mispelled) has been set
tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
}
+ } else if (autoCorrection) {
+ tp.setUnderlineText(mAutoCorrectionUnderlineColor, mAutoCorrectionUnderlineThickness);
}
}
@@ -281,12 +306,15 @@
// The order here should match what is used in updateDrawState
final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+ final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0;
if (easy) {
if (!misspelled) {
return mEasyCorrectUnderlineColor;
} else {
return mMisspelledUnderlineColor;
}
+ } else if (autoCorrection) {
+ return mAutoCorrectionUnderlineColor;
}
return 0;
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 99acb3f..e8ab227 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -416,6 +416,13 @@
public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
/**
+ * Window type: Fake window to consume touch events when the navigation
+ * bar is hidden.
+ * @hide
+ */
+ public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index aaf45e5..bfd2959 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -23,6 +23,7 @@
import android.graphics.RectF;
import android.os.IBinder;
import android.os.LocalPowerManager;
+import android.os.Looper;
import android.view.animation.Animation;
import java.io.FileDescriptor;
@@ -315,6 +316,36 @@
}
/**
+ * Representation of a "fake window" that the policy has added to the
+ * window manager to consume events.
+ */
+ public interface FakeWindow {
+ /**
+ * Remove the fake window from the window manager.
+ */
+ void dismiss();
+ }
+
+ /**
+ * Interface for calling back in to the window manager that is private
+ * between it and the policy.
+ */
+ public interface WindowManagerFuncs {
+ /**
+ * Ask the window manager to re-evaluate the system UI flags.
+ */
+ public void reevaluateStatusBarVisibility();
+
+ /**
+ * Add a fake window to the window manager. This window sits
+ * at the top of the other windows and consumes events.
+ */
+ public FakeWindow addFakeWindow(Looper looper, InputHandler inputHandler,
+ String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
+ boolean hasFocus, boolean touchFullscreen);
+ }
+
+ /**
* Bit mask that is set for all enter transition.
*/
public final int TRANSIT_ENTER_MASK = 0x1000;
@@ -395,6 +426,7 @@
* @param powerManager
*/
public void init(Context context, IWindowManager windowManager,
+ WindowManagerFuncs windowManagerFuncs,
LocalPowerManager powerManager);
/**
@@ -762,7 +794,7 @@
/**
* A new window has been focused.
*/
- public void focusChanged(WindowState lastFocus, WindowState newFocus);
+ public int focusChangedLw(WindowState lastFocus, WindowState newFocus);
/**
* Called after the screen turns off.
@@ -968,6 +1000,14 @@
public void setUserRotationMode(int mode, int rotation);
/**
+ * Called when a new system UI visibility is being reported, allowing
+ * the policy to adjust what is actually reported.
+ * @param visibility The raw visiblity reported by the status bar.
+ * @return The new desired visibility.
+ */
+ public int adjustSystemUiVisibilityLw(int visibility);
+
+ /**
* Print the WindowManagerPolicy's state into the given stream.
*
* @param prefix Text to print at the front of each line.
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 7398262..b85fd17 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -22,16 +22,14 @@
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
-import android.webkit.WebView;
-import android.widget.EditText;
-import android.widget.TextView;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
View.OnLongClickListener, View.OnClickListener {
@@ -203,6 +201,7 @@
@Override
public void onDestroyActionMode(ActionMode mode) {
+ mActionMode = null;
mWebView.notifyFindDialogDismissed();
mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
}
@@ -255,4 +254,13 @@
// Does nothing. Needed to implement TextWatcher.
}
+ public int getActionModeHeight() {
+ if (mActionMode == null) {
+ return 0;
+ }
+ View parent = (View) mCustomView.getParent();
+ return parent != null ? parent.getMeasuredHeight()
+ : mCustomView.getMeasuredHeight();
+ }
+
}
diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java
index 3600d09..9fc48a1 100644
--- a/core/java/android/webkit/HTML5Audio.java
+++ b/core/java/android/webkit/HTML5Audio.java
@@ -16,12 +16,9 @@
package android.webkit;
+import android.content.Context;
+import android.media.AudioManager;
import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnBufferingUpdateListener;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
-import android.media.MediaPlayer.OnPreparedListener;
-import android.media.MediaPlayer.OnSeekCompleteListener;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -45,7 +42,8 @@
MediaPlayer.OnCompletionListener,
MediaPlayer.OnErrorListener,
MediaPlayer.OnPreparedListener,
- MediaPlayer.OnSeekCompleteListener {
+ MediaPlayer.OnSeekCompleteListener,
+ AudioManager.OnAudioFocusChangeListener {
// Logging tag.
private static final String LOGTAG = "HTML5Audio";
@@ -69,6 +67,7 @@
private String mUrl;
private boolean mAskToPlay = false;
+ private Context mContext;
// Timer thread -> UI thread
private static final int TIMEUPDATE = 100;
@@ -183,6 +182,7 @@
// Save the native ptr
mNativePointer = nativePtr;
resetMediaPlayer();
+ mContext = webViewCore.getContext();
mIsPrivateBrowsingEnabledGetter = new IsPrivateBrowsingEnabledGetter(
webViewCore.getContext().getMainLooper(), webViewCore.getWebView());
}
@@ -233,6 +233,34 @@
}
}
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+ switch (focusChange) {
+ case AudioManager.AUDIOFOCUS_GAIN:
+ // resume playback
+ if (mMediaPlayer == null) resetMediaPlayer();
+ else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();
+ mState = STARTED;
+ break;
+
+ case AudioManager.AUDIOFOCUS_LOSS:
+ // Lost focus for an unbounded amount of time: stop playback and release media player
+ if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ break;
+
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ // Lost focus for a short time, but we have to stop
+ // playback. We don't release the media player because playback
+ // is likely to resume
+ if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
+ break;
+ }
+ }
+
+
private void play() {
if ((mState >= ERROR && mState < PREPARED) && mUrl != null) {
resetMediaPlayer();
@@ -241,8 +269,17 @@
}
if (mState >= PREPARED) {
- mMediaPlayer.start();
- mState = STARTED;
+ AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN);
+
+ if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ // could not get audio focus.
+ teardown();
+ } else {
+ mMediaPlayer.start();
+ mState = STARTED;
+ }
}
}
@@ -276,4 +313,5 @@
private native void nativeOnEnded(int nativePointer);
private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
private native void nativeOnTimeupdate(int position, int nativePointer);
+
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d920f27..f46af51 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1483,7 +1483,8 @@
private int getVisibleTitleHeightImpl() {
// need to restrict mScrollY due to over scroll
- return Math.max(getTitleHeight() - Math.max(0, mScrollY), 0);
+ return Math.max(getTitleHeight() - Math.max(0, mScrollY),
+ mFindCallback != null ? mFindCallback.getActionModeHeight() : 0);
}
/*
@@ -2074,6 +2075,11 @@
* be encoded as base64. Otherwise, the data must use ASCII encoding for
* octets inside the range of safe URL characters and use the standard %xx
* hex encoding of URLs for octets outside that range.
+ * <p>
+ * The 'data' scheme URL formed by this method uses the default US-ASCII
+ * charset. If you need need to set a different charset, you should form a
+ * 'data' scheme URL which specifies a charset parameter and call
+ * {@link #loadUrl(String)} instead.
* @param data A String of data in the given encoding.
* @param mimeType The MIMEType of the data, e.g. 'text/html'.
* @param encoding The encoding of the data.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index c218f23..38bb2e1 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -237,9 +237,11 @@
SparseBooleanArray mCheckStates;
/**
- * Running state of which IDs are currently checked
+ * Running state of which IDs are currently checked.
+ * If there is a value for a given key, the checked state for that ID is true
+ * and the value holds the last known position in the adapter for that id.
*/
- LongSparseArray<Boolean> mCheckedIdStates;
+ LongSparseArray<Integer> mCheckedIdStates;
/**
* Controls how the next layout will happen
@@ -472,6 +474,13 @@
static final int OVERSCROLL_LIMIT_DIVISOR = 3;
/**
+ * How many positions in either direction we will search to try to
+ * find a checked item with a stable ID that moved position across
+ * a data set change. If the item isn't found it will be unselected.
+ */
+ private static final int CHECK_POSITION_SEARCH_DISTANCE = 20;
+
+ /**
* Used to request a layout when we changed touch mode
*/
private static final int TOUCH_MODE_UNKNOWN = -1;
@@ -806,7 +815,7 @@
if (adapter != null) {
if (mChoiceMode != CHOICE_MODE_NONE && mAdapter.hasStableIds() &&
mCheckedIdStates == null) {
- mCheckedIdStates = new LongSparseArray<Boolean>();
+ mCheckedIdStates = new LongSparseArray<Integer>();
}
}
@@ -901,7 +910,7 @@
return new long[0];
}
- final LongSparseArray<Boolean> idStates = mCheckedIdStates;
+ final LongSparseArray<Integer> idStates = mCheckedIdStates;
final int count = idStates.size();
final long[] ids = new long[count];
@@ -948,7 +957,7 @@
mCheckStates.put(position, value);
if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
if (value) {
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ mCheckedIdStates.put(mAdapter.getItemId(position), position);
} else {
mCheckedIdStates.delete(mAdapter.getItemId(position));
}
@@ -980,7 +989,7 @@
if (value) {
mCheckStates.put(position, true);
if (updateIds) {
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ mCheckedIdStates.put(mAdapter.getItemId(position), position);
}
mCheckedItemCount = 1;
} else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
@@ -1010,7 +1019,7 @@
mCheckStates.put(position, newValue);
if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
if (newValue) {
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ mCheckedIdStates.put(mAdapter.getItemId(position), position);
} else {
mCheckedIdStates.delete(mAdapter.getItemId(position));
}
@@ -1032,7 +1041,7 @@
mCheckStates.put(position, true);
if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
mCheckedIdStates.clear();
- mCheckedIdStates.put(mAdapter.getItemId(position), Boolean.TRUE);
+ mCheckedIdStates.put(mAdapter.getItemId(position), position);
}
mCheckedItemCount = 1;
} else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
@@ -1081,7 +1090,7 @@
mCheckStates = new SparseBooleanArray();
}
if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
- mCheckedIdStates = new LongSparseArray<Boolean>();
+ mCheckedIdStates = new LongSparseArray<Integer>();
}
// Modal multi-choice mode only has choices when the mode is active. Clear them.
if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
@@ -1411,7 +1420,7 @@
boolean inActionMode;
int checkedItemCount;
SparseBooleanArray checkState;
- LongSparseArray<Boolean> checkIdState;
+ LongSparseArray<Integer> checkIdState;
/**
* Constructor called from {@link AbsListView#onSaveInstanceState()}
@@ -1434,11 +1443,14 @@
inActionMode = in.readByte() != 0;
checkedItemCount = in.readInt();
checkState = in.readSparseBooleanArray();
- long[] idState = in.createLongArray();
-
- if (idState.length > 0) {
- checkIdState = new LongSparseArray<Boolean>();
- checkIdState.setValues(idState, Boolean.TRUE);
+ final int N = in.readInt();
+ if (N > 0) {
+ checkIdState = new LongSparseArray<Integer>();
+ for (int i=0; i<N; i++) {
+ final long key = in.readLong();
+ final int value = in.readInt();
+ checkIdState.put(key, value);
+ }
}
}
@@ -1454,7 +1466,12 @@
out.writeByte((byte) (inActionMode ? 1 : 0));
out.writeInt(checkedItemCount);
out.writeSparseBooleanArray(checkState);
- out.writeLongArray(checkIdState != null ? checkIdState.getKeys() : new long[0]);
+ final int N = checkIdState != null ? checkIdState.size() : 0;
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ out.writeLong(checkIdState.keyAt(i));
+ out.writeInt(checkIdState.valueAt(i));
+ }
}
@Override
@@ -1549,7 +1566,7 @@
ss.checkState = mCheckStates.clone();
}
if (mCheckedIdStates != null) {
- final LongSparseArray<Boolean> idState = new LongSparseArray<Boolean>();
+ final LongSparseArray<Integer> idState = new LongSparseArray<Integer>();
final int count = mCheckedIdStates.size();
for (int i = 0; i < count; i++) {
idState.put(mCheckedIdStates.keyAt(i), mCheckedIdStates.valueAt(i));
@@ -4770,15 +4787,63 @@
return selectedPos >= 0;
}
+ void confirmCheckedPositionsById() {
+ // Clear out the positional check states, we'll rebuild it below from IDs.
+ mCheckStates.clear();
+
+ boolean checkedCountChanged = false;
+ for (int checkedIndex = 0; checkedIndex < mCheckedIdStates.size(); checkedIndex++) {
+ final long id = mCheckedIdStates.keyAt(checkedIndex);
+ final int lastPos = mCheckedIdStates.valueAt(checkedIndex);
+
+ final long lastPosId = mAdapter.getItemId(lastPos);
+ if (id != lastPosId) {
+ // Look around to see if the ID is nearby. If not, uncheck it.
+ final int start = Math.max(0, lastPos - CHECK_POSITION_SEARCH_DISTANCE);
+ final int end = Math.min(lastPos + CHECK_POSITION_SEARCH_DISTANCE, mItemCount);
+ boolean found = false;
+ for (int searchPos = start; searchPos < end; searchPos++) {
+ final long searchId = mAdapter.getItemId(searchPos);
+ if (id == searchId) {
+ found = true;
+ mCheckStates.put(searchPos, true);
+ mCheckedIdStates.setValueAt(checkedIndex, searchPos);
+ break;
+ }
+ }
+
+ if (!found) {
+ mCheckedIdStates.delete(id);
+ checkedIndex--;
+ mCheckedItemCount--;
+ checkedCountChanged = true;
+ if (mChoiceActionMode != null && mMultiChoiceModeCallback != null) {
+ mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
+ lastPos, id, false);
+ }
+ }
+ } else {
+ mCheckStates.put(lastPos, true);
+ }
+ }
+
+ if (checkedCountChanged && mChoiceActionMode != null) {
+ mChoiceActionMode.invalidate();
+ }
+ }
+
@Override
protected void handleDataChanged() {
int count = mItemCount;
int lastHandledItemCount = mLastHandledItemCount;
mLastHandledItemCount = mItemCount;
+
+ if (mChoiceMode != CHOICE_MODE_NONE && mAdapter != null && mAdapter.hasStableIds()) {
+ confirmCheckedPositionsById();
+ }
+
if (count > 0) {
-
int newPos;
-
int selectablePos;
// Find the row we are supposed to sync to
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 351714e..6a0cd36 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -68,6 +68,7 @@
void noteScanWifiLockReleasedFromSource(in WorkSource ws);
void noteWifiMulticastEnabledFromSource(in WorkSource ws);
void noteWifiMulticastDisabledFromSource(in WorkSource ws);
+ void noteNetworkInterfaceType(String iface, int type);
void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/app/RingtonePickerActivity.java b/core/java/com/android/internal/app/RingtonePickerActivity.java
index 719847e..36fc24e 100644
--- a/core/java/com/android/internal/app/RingtonePickerActivity.java
+++ b/core/java/com/android/internal/app/RingtonePickerActivity.java
@@ -47,7 +47,9 @@
private static final String TAG = "RingtonePickerActivity";
private static final int DELAY_MS_SELECTION_PLAYED = 300;
-
+
+ private static final String SAVE_CLICKED_POS = "clicked_pos";
+
private RingtoneManager mRingtoneManager;
private Cursor mCursor;
@@ -120,7 +122,10 @@
if (mUriForDefaultItem == null) {
mUriForDefaultItem = Settings.System.DEFAULT_RINGTONE_URI;
}
-
+
+ if (savedInstanceState != null) {
+ mClickedPos = savedInstanceState.getInt(SAVE_CLICKED_POS, -1);
+ }
// Get whether to show the 'Silent' item
mHasSilentItem = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
@@ -167,6 +172,12 @@
setupAlert();
}
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(SAVE_CLICKED_POS, mClickedPos);
+ }
+
public void onPrepareListView(ListView listView) {
if (mHasDefaultItem) {
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
new file mode 100644
index 0000000..ee3f23b
--- /dev/null
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.net;
+
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
+
+import android.net.NetworkStats;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+import com.google.android.collect.Sets;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+import libcore.io.IoUtils;
+
+/**
+ * Creates {@link NetworkStats} instances by parsing various {@code /proc/}
+ * files as needed.
+ */
+public class NetworkStatsFactory {
+ private static final String TAG = "NetworkStatsFactory";
+
+ // TODO: consider moving parsing to native code
+
+ /** Path to {@code /proc/net/dev}. */
+ @Deprecated
+ private final File mStatsIface;
+ /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
+ @Deprecated
+ private final File mStatsXtIface;
+ /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
+ private final File mStatsXtIfaceAll;
+ /** Path to {@code /proc/net/xt_qtaguid/stats}. */
+ private final File mStatsXtUid;
+
+ /** {@link #mStatsXtUid} and {@link #mStatsXtIfaceAll} headers. */
+ private static final String KEY_IDX = "idx";
+ private static final String KEY_IFACE = "iface";
+ private static final String KEY_ACTIVE = "active";
+ private static final String KEY_UID = "uid_tag_int";
+ private static final String KEY_COUNTER_SET = "cnt_set";
+ private static final String KEY_TAG_HEX = "acct_tag_hex";
+ private static final String KEY_SNAP_RX_BYTES = "snap_rx_bytes";
+ private static final String KEY_SNAP_RX_PACKETS = "snap_rx_packets";
+ private static final String KEY_SNAP_TX_BYTES = "snap_tx_bytes";
+ private static final String KEY_SNAP_TX_PACKETS = "snap_tx_packets";
+ private static final String KEY_RX_BYTES = "rx_bytes";
+ private static final String KEY_RX_PACKETS = "rx_packets";
+ private static final String KEY_TX_BYTES = "tx_bytes";
+ private static final String KEY_TX_PACKETS = "tx_packets";
+
+ public NetworkStatsFactory() {
+ this(new File("/proc/"));
+ }
+
+ // @VisibleForTesting
+ public NetworkStatsFactory(File procRoot) {
+ mStatsIface = new File(procRoot, "net/dev");
+ mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
+ mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
+ mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
+ }
+
+ /**
+ * Parse and return interface-level summary {@link NetworkStats}. Values
+ * monotonically increase since device boot, and may include details about
+ * inactive interfaces.
+ *
+ * @throws IllegalStateException when problem parsing stats.
+ */
+ public NetworkStats readNetworkStatsSummary() throws IllegalStateException {
+ if (mStatsXtIfaceAll.exists()) {
+ return readNetworkStatsSummarySingleFile();
+ } else {
+ return readNetworkStatsSummaryMultipleFiles();
+ }
+ }
+
+ private NetworkStats readNetworkStatsSummarySingleFile() {
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+
+ // TODO: read directly from proc once headers are added
+ final ArrayList<String> keys = Lists.newArrayList(KEY_IFACE, KEY_ACTIVE, KEY_SNAP_RX_BYTES,
+ KEY_SNAP_RX_PACKETS, KEY_SNAP_TX_BYTES, KEY_SNAP_TX_PACKETS, KEY_RX_BYTES,
+ KEY_RX_PACKETS, KEY_TX_BYTES, KEY_TX_PACKETS);
+ final ArrayList<String> values = Lists.newArrayList();
+ final HashMap<String, String> parsed = Maps.newHashMap();
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(mStatsXtIfaceAll));
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ splitLine(line, values);
+ parseLine(keys, values, parsed);
+
+ entry.iface = parsed.get(KEY_IFACE);
+ entry.uid = UID_ALL;
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+
+ // always include snapshot values
+ entry.rxBytes = getParsedLong(parsed, KEY_SNAP_RX_BYTES);
+ entry.rxPackets = getParsedLong(parsed, KEY_SNAP_RX_PACKETS);
+ entry.txBytes = getParsedLong(parsed, KEY_SNAP_TX_BYTES);
+ entry.txPackets = getParsedLong(parsed, KEY_SNAP_TX_PACKETS);
+
+ // fold in active numbers, but only when active
+ final boolean active = getParsedInt(parsed, KEY_ACTIVE) != 0;
+ if (active) {
+ entry.rxBytes += getParsedLong(parsed, KEY_RX_BYTES);
+ entry.rxPackets += getParsedLong(parsed, KEY_RX_PACKETS);
+ entry.txBytes += getParsedLong(parsed, KEY_TX_BYTES);
+ entry.txPackets += getParsedLong(parsed, KEY_TX_PACKETS);
+ }
+
+ stats.addValues(entry);
+ }
+ } catch (NullPointerException e) {
+ throw new IllegalStateException("problem parsing stats: " + e);
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException("problem parsing stats: " + e);
+ } catch (IOException e) {
+ throw new IllegalStateException("problem parsing stats: " + e);
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+ return stats;
+ }
+
+ /**
+ * @deprecated remove once {@code iface_stat_all} is merged to all kernels.
+ */
+ @Deprecated
+ private NetworkStats readNetworkStatsSummaryMultipleFiles() {
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+
+ final HashSet<String> knownIfaces = Sets.newHashSet();
+ final HashSet<String> activeIfaces = Sets.newHashSet();
+
+ // collect any historical stats and active state
+ for (String iface : fileListWithoutNull(mStatsXtIface)) {
+ final File ifacePath = new File(mStatsXtIface, iface);
+
+ final long active = readSingleLongFromFile(new File(ifacePath, "active"));
+ if (active == 1) {
+ knownIfaces.add(iface);
+ activeIfaces.add(iface);
+ } else if (active == 0) {
+ knownIfaces.add(iface);
+ } else {
+ continue;
+ }
+
+ entry.iface = iface;
+ entry.uid = UID_ALL;
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
+ entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
+ entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
+ entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
+
+ stats.addValues(entry);
+ }
+
+ final ArrayList<String> values = Lists.newArrayList();
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(mStatsIface));
+
+ // skip first two header lines
+ reader.readLine();
+ reader.readLine();
+
+ // parse remaining lines
+ String line;
+ while ((line = reader.readLine()) != null) {
+ splitLine(line, values);
+
+ try {
+ entry.iface = values.get(0);
+ entry.uid = UID_ALL;
+ entry.set = SET_DEFAULT;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = Long.parseLong(values.get(1));
+ entry.rxPackets = Long.parseLong(values.get(2));
+ entry.txBytes = Long.parseLong(values.get(9));
+ entry.txPackets = Long.parseLong(values.get(10));
+
+ if (activeIfaces.contains(entry.iface)) {
+ // combine stats when iface is active
+ stats.combineValues(entry);
+ } else if (!knownIfaces.contains(entry.iface)) {
+ // add stats when iface is unknown
+ stats.addValues(entry);
+ }
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
+ }
+ }
+ } catch (NullPointerException e) {
+ throw new IllegalStateException("problem parsing stats: " + e);
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException("problem parsing stats: " + e);
+ } catch (IOException e) {
+ throw new IllegalStateException("problem parsing stats: " + e);
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+
+ return stats;
+ }
+
+ public NetworkStats readNetworkStatsDetail() {
+ return readNetworkStatsDetail(UID_ALL);
+ }
+
+ /**
+ * Parse and return {@link NetworkStats} with UID-level details. Values
+ * monotonically increase since device boot.
+ *
+ * @throws IllegalStateException when problem parsing stats.
+ */
+ public NetworkStats readNetworkStatsDetail(int limitUid) throws IllegalStateException {
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+
+ // TODO: remove knownLines check once 5087722 verified
+ final HashSet<String> knownLines = Sets.newHashSet();
+ // TODO: remove lastIdx check once 5270106 verified
+ int lastIdx;
+
+ final ArrayList<String> keys = Lists.newArrayList();
+ final ArrayList<String> values = Lists.newArrayList();
+ final HashMap<String, String> parsed = Maps.newHashMap();
+
+ BufferedReader reader = null;
+ String line = null;
+ try {
+ reader = new BufferedReader(new FileReader(mStatsXtUid));
+
+ // parse first line as header
+ line = reader.readLine();
+ splitLine(line, keys);
+ lastIdx = 1;
+
+ // parse remaining lines
+ while ((line = reader.readLine()) != null) {
+ splitLine(line, values);
+ parseLine(keys, values, parsed);
+
+ if (!knownLines.add(line)) {
+ throw new IllegalStateException("duplicate proc entry: " + line);
+ }
+
+ final int idx = getParsedInt(parsed, KEY_IDX);
+ if (idx != lastIdx + 1) {
+ throw new IllegalStateException(
+ "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
+ }
+ lastIdx = idx;
+
+ entry.iface = parsed.get(KEY_IFACE);
+ entry.uid = getParsedInt(parsed, KEY_UID);
+ entry.set = getParsedInt(parsed, KEY_COUNTER_SET);
+ entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
+ entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
+ entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
+ entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
+ entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
+
+ if (limitUid == UID_ALL || limitUid == entry.uid) {
+ stats.addValues(entry);
+ }
+ }
+ } catch (NullPointerException e) {
+ throw new IllegalStateException("problem parsing line: " + line, e);
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException("problem parsing line: " + line, e);
+ } catch (IOException e) {
+ throw new IllegalStateException("problem parsing line: " + line, e);
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+ return stats;
+ }
+
+ private static int getParsedInt(HashMap<String, String> parsed, String key) {
+ final String value = parsed.get(key);
+ return value != null ? Integer.parseInt(value) : 0;
+ }
+
+ private static long getParsedLong(HashMap<String, String> parsed, String key) {
+ final String value = parsed.get(key);
+ return value != null ? Long.parseLong(value) : 0;
+ }
+
+ /**
+ * Split given line into {@link ArrayList}.
+ */
+ private static void splitLine(String line, ArrayList<String> outSplit) {
+ outSplit.clear();
+
+ final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
+ while (t.hasMoreTokens()) {
+ outSplit.add(t.nextToken());
+ }
+ }
+
+ /**
+ * Zip the two given {@link ArrayList} as key and value pairs into
+ * {@link HashMap}.
+ */
+ private static void parseLine(
+ ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
+ outParsed.clear();
+
+ final int size = Math.min(keys.size(), values.size());
+ for (int i = 0; i < size; i++) {
+ outParsed.put(keys.get(i), values.get(i));
+ }
+ }
+
+ /**
+ * Utility method to read a single plain-text {@link Long} from the given
+ * {@link File}, usually from a {@code /proc/} filesystem.
+ */
+ private static long readSingleLongFromFile(File file) {
+ try {
+ final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
+ return Long.parseLong(new String(buffer).trim());
+ } catch (NumberFormatException e) {
+ return -1;
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ /**
+ * Wrapper for {@link File#list()} that returns empty array instead of
+ * {@code null}.
+ */
+ private static String[] fileListWithoutNull(File file) {
+ final String[] list = file.list();
+ return list != null ? list : new String[0];
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index df5071f..e2a2566 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,11 +16,15 @@
package com.android.internal.os;
-import com.android.internal.util.JournaledFile;
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.UID_ALL;
+import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
-import android.net.TrafficStats;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkStats;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.FileUtils;
@@ -43,6 +47,11 @@
import android.util.SparseArray;
import android.util.TimeUtils;
+import com.android.internal.R;
+import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.util.JournaledFile;
+import com.google.android.collect.Sets;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
@@ -52,6 +61,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -69,6 +79,8 @@
private static final boolean DEBUG_HISTORY = false;
private static final boolean USE_OLD_HISTORY = false; // for debugging.
+ // TODO: remove "tcp" from network methods, since we measure total stats.
+
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
@@ -314,6 +326,11 @@
private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
+ private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
+
+ /** Network ifaces that {@link ConnectivityManager} has claimed as mobile. */
+ private HashSet<String> mMobileIfaces = Sets.newHashSet();
+
// For debugging
public BatteryStatsImpl() {
mFile = null;
@@ -1036,7 +1053,8 @@
String name;
int count;
long totalTime;
- int startIndex, endIndex;
+ int startIndex;
+ int endIndex;
int numUpdatedWlNames = 0;
// Advance past the first line.
@@ -1390,30 +1408,48 @@
}
public void doUnplugLocked(long batteryUptime, long batteryRealtime) {
- for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
- Uid u = mUidStats.valueAt(iu);
- u.mStartedTcpBytesReceived = TrafficStats.getUidRxBytes(u.mUid);
- u.mStartedTcpBytesSent = TrafficStats.getUidTxBytes(u.mUid);
+ NetworkStats.Entry entry = null;
+
+ // Track UID data usage
+ final NetworkStats uidStats = getNetworkStatsDetailGroupedByUid();
+ final int size = uidStats.size();
+ for (int i = 0; i < size; i++) {
+ entry = uidStats.getValues(i, entry);
+
+ final Uid u = mUidStats.get(entry.uid);
+ if (u == null) continue;
+
+ u.mStartedTcpBytesReceived = entry.rxBytes;
+ u.mStartedTcpBytesSent = entry.txBytes;
u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
}
+
for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
}
- // Track total mobile data
- doDataUnplug(mMobileDataRx, TrafficStats.getMobileRxBytes());
- doDataUnplug(mMobileDataTx, TrafficStats.getMobileTxBytes());
- doDataUnplug(mTotalDataRx, TrafficStats.getTotalRxBytes());
- doDataUnplug(mTotalDataTx, TrafficStats.getTotalTxBytes());
+
+ // Track both mobile and total overall data
+ final NetworkStats ifaceStats = getNetworkStatsSummary();
+ entry = ifaceStats.getTotal(entry, mMobileIfaces);
+ doDataUnplug(mMobileDataRx, entry.rxBytes);
+ doDataUnplug(mMobileDataTx, entry.txBytes);
+ entry = ifaceStats.getTotal(entry);
+ doDataUnplug(mTotalDataRx, entry.rxBytes);
+ doDataUnplug(mTotalDataTx, entry.txBytes);
+
// Track radio awake time
mRadioDataStart = getCurrentRadioDataUptime();
mRadioDataUptime = 0;
+
// Track bt headset ping count
mBluetoothPingStart = getCurrentBluetoothPingCount();
mBluetoothPingCount = 0;
}
public void doPlugLocked(long batteryUptime, long batteryRealtime) {
+ NetworkStats.Entry entry = null;
+
for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
Uid u = mUidStats.valueAt(iu);
if (u.mStartedTcpBytesReceived >= 0) {
@@ -1428,10 +1464,16 @@
for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
}
- doDataPlug(mMobileDataRx, TrafficStats.getMobileRxBytes());
- doDataPlug(mMobileDataTx, TrafficStats.getMobileTxBytes());
- doDataPlug(mTotalDataRx, TrafficStats.getTotalRxBytes());
- doDataPlug(mTotalDataTx, TrafficStats.getTotalTxBytes());
+
+ // Track both mobile and total overall data
+ final NetworkStats ifaceStats = getNetworkStatsSummary();
+ entry = ifaceStats.getTotal(entry, mMobileIfaces);
+ doDataPlug(mMobileDataRx, entry.rxBytes);
+ doDataPlug(mMobileDataTx, entry.txBytes);
+ entry = ifaceStats.getTotal(entry);
+ doDataPlug(mTotalDataRx, entry.rxBytes);
+ doDataPlug(mTotalDataTx, entry.txBytes);
+
// Track radio awake time
mRadioDataUptime = getRadioDataUptime();
mRadioDataStart = -1;
@@ -2216,6 +2258,14 @@
}
}
+ public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
+ if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
+ mMobileIfaces.add(iface);
+ } else {
+ mMobileIfaces.remove(iface);
+ }
+ }
+
@Override public long getScreenOnTime(long batteryRealtime, int which) {
return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@@ -2400,8 +2450,10 @@
}
public long computeCurrentTcpBytesReceived() {
+ final long uidRxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
+ null, mUid).rxBytes;
return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
- ? (TrafficStats.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
+ ? (uidRxBytes - mStartedTcpBytesReceived) : 0);
}
@Override
@@ -2619,8 +2671,10 @@
}
public long computeCurrentTcpBytesSent() {
+ final long uidTxBytes = getNetworkStatsDetailGroupedByUid().getTotal(
+ null, mUid).txBytes;
return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
- ? (TrafficStats.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
+ ? (uidTxBytes - mStartedTcpBytesSent) : 0);
}
/**
@@ -4518,22 +4572,26 @@
/** Only STATS_UNPLUGGED works properly */
public long getMobileTcpBytesSent(int which) {
- return getTcpBytes(TrafficStats.getMobileTxBytes(), mMobileDataTx, which);
+ final long mobileTxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).txBytes;
+ return getTcpBytes(mobileTxBytes, mMobileDataTx, which);
}
/** Only STATS_UNPLUGGED works properly */
public long getMobileTcpBytesReceived(int which) {
- return getTcpBytes(TrafficStats.getMobileRxBytes(), mMobileDataRx, which);
+ final long mobileRxBytes = getNetworkStatsSummary().getTotal(null, mMobileIfaces).rxBytes;
+ return getTcpBytes(mobileRxBytes, mMobileDataRx, which);
}
/** Only STATS_UNPLUGGED works properly */
public long getTotalTcpBytesSent(int which) {
- return getTcpBytes(TrafficStats.getTotalTxBytes(), mTotalDataTx, which);
+ final long totalTxBytes = getNetworkStatsSummary().getTotal(null).txBytes;
+ return getTcpBytes(totalTxBytes, mTotalDataTx, which);
}
/** Only STATS_UNPLUGGED works properly */
public long getTotalTcpBytesReceived(int which) {
- return getTcpBytes(TrafficStats.getTotalRxBytes(), mTotalDataRx, which);
+ final long totalRxBytes = getNetworkStatsSummary().getTotal(null).rxBytes;
+ return getTcpBytes(totalRxBytes, mTotalDataRx, which);
}
@Override
@@ -5637,7 +5695,47 @@
mGlobalWifiRunningTimer.logState(pr, " ");
pr.println("*** Bluetooth timer:");
mBluetoothOnTimer.logState(pr, " ");
+ pr.println("*** Mobile ifaces:");
+ pr.println(mMobileIfaces.toString());
}
super.dumpLocked(pw);
}
+
+ private NetworkStats mNetworkSummaryCache;
+ private NetworkStats mNetworkDetailCache;
+
+ private NetworkStats getNetworkStatsSummary() {
+ // NOTE: calls from BatteryStatsService already hold this lock
+ synchronized (this) {
+ if (mNetworkSummaryCache == null
+ || mNetworkSummaryCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
+ try {
+ mNetworkSummaryCache = mNetworkStatsFactory.readNetworkStatsSummary();
+ } catch (IllegalStateException e) {
+ // log problem and return empty object
+ Log.wtf(TAG, "problem reading network stats", e);
+ mNetworkSummaryCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
+ }
+ }
+ return mNetworkSummaryCache;
+ }
+ }
+
+ private NetworkStats getNetworkStatsDetailGroupedByUid() {
+ // NOTE: calls from BatteryStatsService already hold this lock
+ synchronized (this) {
+ if (mNetworkDetailCache == null
+ || mNetworkDetailCache.getElapsedRealtimeAge() > SECOND_IN_MILLIS) {
+ try {
+ mNetworkDetailCache = mNetworkStatsFactory
+ .readNetworkStatsDetail().groupedByUid();
+ } catch (IllegalStateException e) {
+ // log problem and return empty object
+ Log.wtf(TAG, "problem reading network stats", e);
+ mNetworkDetailCache = new NetworkStats(SystemClock.elapsedRealtime(), 0);
+ }
+ }
+ return mNetworkDetailCache;
+ }
+ }
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 3916e86..aca1fa2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -34,7 +34,6 @@
void topAppWindowChanged(boolean menuVisible);
void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
void setHardKeyboardStatus(boolean available, boolean enabled);
- void userActivity();
void toggleRecentApps();
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 07430e7..ecebfc0 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -46,6 +46,5 @@
void onNotificationClear(String pkg, String tag, int id);
void setSystemUiVisibility(int vis);
void setHardKeyboardEnabled(boolean enabled);
- void userActivity();
void toggleRecentApps();
}
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 02c5bb3..7724646 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -767,20 +767,17 @@
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, textArray, contextCount, flags);
+ value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
+ contextCount, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
}
#else
value = new TextLayoutCacheValue();
- value->computeValues(paint, textArray, contextCount, flags);
+ value->computeValues(paint, textArray, start, count, contextCount, flags);
#endif
- size_t startIndex = 0;
- size_t glyphsCount = 0;
- value->getGlyphsIndexAndCount(start, count, &startIndex, &glyphsCount);
- const jchar* glyphs = value->getGlyphs(startIndex, glyphsCount);
- doDrawGlyphs(canvas, glyphs, 0, glyphsCount, x, y, flags, paint);
+ doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint);
}
static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 3daf7d0..2ab7da9 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -483,18 +483,15 @@
}
jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
- HB_ShaperItem shaperItem;
- HB_FontRec font;
- FontData fontData;
- TextLayoutCacheValue::shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, text,
- start, count, contextCount, flags);
- int glyphCount = shaperItem.num_glyphs;
- for (int i = 0; i < glyphCount; i++) {
- glyphsArray[i] = (jchar) shaperItem.glyphs[i];
- }
+ TextLayoutCacheValue value;
+ value.computeValues(paint, text, start, count, contextCount, flags);
+ const jchar* shapedGlyphs = value.getGlyphs();
+ size_t glyphsCount = value.getGlyphsCount();
+ memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
+
env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
- return glyphCount;
+ return glyphsCount;
}
static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index ae17aed..9b424f2 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -257,17 +257,18 @@
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
// Return advances from the cache. Compute them if needed
- value = TextLayoutCache::getInstance().getValue(paint, chars, contextCount, dirFlags);
+ value = TextLayoutCache::getInstance().getValue(paint, chars, start, count,
+ contextCount, dirFlags);
#else
value = new TextLayoutCacheValue();
- value->computeValues(paint, chars, contextCount, dirFlags);
+ value->computeValues(paint, chars, start, count, contextCount, dirFlags);
#endif
if (value != NULL) {
- if (resultAdvances != NULL) {
- value->getAdvances(start, count, resultAdvances);
+ if (resultAdvances) {
+ memcpy(resultAdvances, value->getAdvances(), value->getAdvancesCount() * sizeof(jfloat));
}
if (resultTotalAdvance) {
- *resultTotalAdvance = value->getTotalAdvance(start, count);
+ *resultTotalAdvance = value->getTotalAdvance();
}
}
}
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 9ba95bd..0b53850 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -106,7 +106,7 @@
* Caching
*/
sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint,
- const jchar* text, jint count, jint dirFlags) {
+ const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
AutoMutex _l(mLock);
nsecs_t startTime = 0;
if (mDebugEnabled) {
@@ -114,7 +114,7 @@
}
// Create the key
- TextLayoutCacheKey key(paint, text, count, dirFlags);
+ TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
// Get value from cache if possible
sp<TextLayoutCacheValue> value = mCache.get(key);
@@ -128,7 +128,7 @@
value = new TextLayoutCacheValue();
// Compute advances and store them
- value->computeValues(paint, text, count, dirFlags);
+ value->computeValues(paint, text, start, count, contextCount, dirFlags);
nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -166,10 +166,10 @@
} else {
if (mDebugEnabled) {
LOGD("CACHE MISS: Calculated but not storing entry because it is too big "
- "with count=%d, "
+ "with start=%d count=%d contextCount=%d, "
"entry size %d bytes, remaining space %d bytes"
" - Compute time in nanos: %lld - Text='%s'",
- count, size, mMaxSize - mSize, endTime,
+ start, count, contextCount, size, mMaxSize - mSize, endTime,
String8(text, count).string());
}
value.clear();
@@ -184,10 +184,10 @@
if (value->getElapsedTime() > 0) {
float deltaPercent = 100 * ((value->getElapsedTime() - elapsedTimeThruCacheGet)
/ ((float)value->getElapsedTime()));
- LOGD("CACHE HIT #%d with count=%d "
+ LOGD("CACHE HIT #%d with start=%d count=%d contextCount=%d"
"- Compute time in nanos: %d - "
"Cache get time in nanos: %lld - Gain in percent: %2.2f - Text='%s' ",
- mCacheHitCount, count,
+ mCacheHitCount, start, count, contextCount,
value->getElapsedTime(), elapsedTimeThruCacheGet, deltaPercent,
String8(text, count).string());
}
@@ -218,14 +218,14 @@
/**
* TextLayoutCacheKey
*/
-TextLayoutCacheKey::TextLayoutCacheKey(): text(NULL), count(0),
+TextLayoutCacheKey::TextLayoutCacheKey(): text(NULL), start(0), count(0), contextCount(0),
dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
hinting(SkPaint::kNo_Hinting) {
}
-TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint,
- const UChar* text, size_t count, int dirFlags) :
- text(text), count(count),
+TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
+ size_t start, size_t count, size_t contextCount, int dirFlags) :
+ text(text), start(start), count(count), contextCount(contextCount),
dirFlags(dirFlags) {
typeface = paint->getTypeface();
textSize = paint->getTextSize();
@@ -238,7 +238,9 @@
TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
text(NULL),
textCopy(other.textCopy),
+ start(other.start),
count(other.count),
+ contextCount(other.contextCount),
dirFlags(other.dirFlags),
typeface(other.typeface),
textSize(other.textSize),
@@ -252,7 +254,13 @@
}
int TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
- int deltaInt = lhs.count - rhs.count;
+ int deltaInt = lhs.start - rhs.start;
+ if (deltaInt != 0) return (deltaInt);
+
+ deltaInt = lhs.count - rhs.count;
+ if (deltaInt != 0) return (deltaInt);
+
+ deltaInt = lhs.contextCount - rhs.contextCount;
if (deltaInt != 0) return (deltaInt);
if (lhs.typeface < rhs.typeface) return -1;
@@ -276,16 +284,16 @@
deltaInt = lhs.dirFlags - rhs.dirFlags;
if (deltaInt) return (deltaInt);
- return memcmp(lhs.getText(), rhs.getText(), lhs.count * sizeof(UChar));
+ return memcmp(lhs.getText(), rhs.getText(), lhs.contextCount * sizeof(UChar));
}
void TextLayoutCacheKey::internalTextCopy() {
- textCopy.setTo(text, count);
+ textCopy.setTo(text, contextCount);
text = NULL;
}
size_t TextLayoutCacheKey::getSize() {
- return sizeof(TextLayoutCacheKey) + sizeof(UChar) * count;
+ return sizeof(TextLayoutCacheKey) + sizeof(UChar) * contextCount;
}
/**
@@ -304,29 +312,32 @@
}
void TextLayoutCacheValue::computeValues(SkPaint* paint, const UChar* chars,
- size_t contextCount, int dirFlags) {
+ size_t start, size_t count, size_t contextCount, int dirFlags) {
// Give a hint for advances, glyphs and log clusters vectors size
mAdvances.setCapacity(contextCount);
mGlyphs.setCapacity(contextCount);
- mLogClusters.setCapacity(contextCount);
- computeValuesWithHarfbuzz(paint, chars, contextCount, dirFlags,
- &mAdvances, &mTotalAdvance, &mGlyphs, &mLogClusters);
+ computeValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
+ &mAdvances, &mTotalAdvance, &mGlyphs);
#if DEBUG_ADVANCES
- LOGD("Advances - countextCount=%d - totalAdvance=%f", contextCount, mTotalAdvance);
+ LOGD("Advances - start=%d, count=%d, countextCount=%d, totalAdvance=%f", start, count,
+ contextCount, mTotalAdvance);
#endif
}
size_t TextLayoutCacheValue::getSize() {
return sizeof(TextLayoutCacheValue) + sizeof(jfloat) * mAdvances.capacity() +
- sizeof(jchar) * mGlyphs.capacity() + sizeof(unsigned short) * mLogClusters.capacity();
+ sizeof(jchar) * mGlyphs.capacity();
}
-void TextLayoutCacheValue::setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font,
- FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count,
- size_t contextCount, bool isRTL) {
+void TextLayoutCacheValue::initShaperItem(HB_ShaperItem& shaperItem, HB_FontRec* font,
+ FontData* fontData, SkPaint* paint, const UChar* chars, size_t contextCount) {
+ // Zero the Shaper struct
+ memset(&shaperItem, 0, sizeof(shaperItem));
+
font->klass = &harfbuzzSkiaClass;
font->userData = 0;
+
// The values which harfbuzzSkiaClass returns are already scaled to
// pixel units, so we just set all these to one to disable further
// scaling.
@@ -335,33 +346,13 @@
font->x_scale = 1;
font->y_scale = 1;
- memset(shaperItem, 0, sizeof(*shaperItem));
- shaperItem->font = font;
- shaperItem->face = HB_NewFace(shaperItem->font, harfbuzzSkiaGetTable);
+ shaperItem.font = font;
+ shaperItem.face = HB_NewFace(shaperItem.font, harfbuzzSkiaGetTable);
- shaperItem->kerning_applied = false;
+ // Reset kerning
+ shaperItem.kerning_applied = false;
- // We cannot know, ahead of time, how many glyphs a given script run
- // will produce. We take a guess that script runs will not produce more
- // than twice as many glyphs as there are code points plus a bit of
- // padding and fallback if we find that we are wrong.
- createGlyphArrays(shaperItem, (contextCount + 2) * 2);
-
- // Free memory for clusters if needed and recreate the clusters array
- if (shaperItem->log_clusters) {
- delete shaperItem->log_clusters;
- }
- shaperItem->log_clusters = new unsigned short[contextCount];
-
- shaperItem->item.pos = start;
- shaperItem->item.length = count;
- shaperItem->item.bidiLevel = isRTL;
-
- shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common;
-
- shaperItem->string = chars;
- shaperItem->stringLength = contextCount;
-
+ // Define font data
fontData->typeFace = paint->getTypeface();
fontData->textSize = paint->getTextSize();
fontData->textSkewX = paint->getTextSkewX();
@@ -369,31 +360,50 @@
fontData->flags = paint->getFlags();
fontData->hinting = paint->getHinting();
- shaperItem->font->userData = fontData;
+ shaperItem.font->userData = fontData;
+
+ // We cannot know, ahead of time, how many glyphs a given script run
+ // will produce. We take a guess that script runs will not produce more
+ // than twice as many glyphs as there are code points plus a bit of
+ // padding and fallback if we find that we are wrong.
+ createGlyphArrays(shaperItem, (contextCount + 2) * 2);
+
+ // Create log clusters array
+ shaperItem.log_clusters = new unsigned short[contextCount];
+
+ // Set the string properties
+ shaperItem.string = chars;
+ shaperItem.stringLength = contextCount;
}
-void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font,
- FontData* fontData, SkPaint* paint, const UChar* chars, size_t start, size_t count,
- size_t contextCount, bool isRTL) {
- // Setup Harfbuzz Shaper
- setupShaperItem(shaperItem, font, fontData, paint, chars, start, count,
- contextCount, isRTL);
+void TextLayoutCacheValue::freeShaperItem(HB_ShaperItem& shaperItem) {
+ deleteGlyphArrays(shaperItem);
+ delete[] shaperItem.log_clusters;
+ HB_FreeFace(shaperItem.face);
+}
+
+void TextLayoutCacheValue::shapeRun(HB_ShaperItem& shaperItem, size_t start, size_t count,
+ bool isRTL) {
+ // Update Harfbuzz Shaper
+ shaperItem.item.pos = start;
+ shaperItem.item.length = count;
+ shaperItem.item.bidiLevel = isRTL;
+
+ shaperItem.item.script = isRTL ? HB_Script_Arabic : HB_Script_Common;
// Shape
- resetGlyphArrays(shaperItem);
- while (!HB_ShapeItem(shaperItem)) {
+ while (!HB_ShapeItem(&shaperItem)) {
// We overflowed our arrays. Resize and retry.
// HB_ShapeItem fills in shaperItem.num_glyphs with the needed size.
deleteGlyphArrays(shaperItem);
- createGlyphArrays(shaperItem, shaperItem->num_glyphs << 1);
- resetGlyphArrays(shaperItem);
+ createGlyphArrays(shaperItem, shaperItem.num_glyphs << 1);
}
}
void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
- size_t contextCount, int dirFlags,
+ size_t start, size_t count, size_t contextCount, int dirFlags,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
- Vector<jchar>* const outGlyphs, Vector<unsigned short>* const outLogClusters) {
+ Vector<jchar>* const outGlyphs) {
UBiDiLevel bidiReq = 0;
bool forceLTR = false;
@@ -408,13 +418,21 @@
case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
}
+ HB_ShaperItem shaperItem;
+ HB_FontRec font;
+ FontData fontData;
+
+ // Initialize Harfbuzz Shaper
+ initShaperItem(shaperItem, &font, &fontData, paint, chars, contextCount);
+
if (forceLTR || forceRTL) {
#if DEBUG_GLYPHS
LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d",
forceLTR, forceRTL);
#endif
- computeRunValuesWithHarfbuzz(paint, chars, 0, contextCount, contextCount, forceRTL,
- outAdvances, outTotalAdvance, outGlyphs, outLogClusters);
+ computeRunValuesWithHarfbuzz(shaperItem, paint,
+ start, count, forceRTL,
+ outAdvances, outTotalAdvance, outGlyphs);
} else {
UBiDi* bidi = ubidi_open();
if (bidi) {
@@ -427,32 +445,49 @@
int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
size_t rc = ubidi_countRuns(bidi, &status);
#if DEBUG_GLYPHS
- LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d", dirFlags, rc, paraDir);
+ LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d",
+ dirFlags, rc, paraDir);
#endif
if (rc == 1 || !U_SUCCESS(status)) {
bool isRTL = (paraDir == 1);
#if DEBUG_GLYPHS
LOGD("computeValuesWithHarfbuzz -- processing SINGLE run "
- "-- run-start=%d run-len=%d isRTL=%d", 0, contextCount, isRTL);
+ "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL);
#endif
- computeRunValuesWithHarfbuzz(paint, chars, 0, contextCount, contextCount,
- isRTL, outAdvances, outTotalAdvance, outGlyphs, outLogClusters);
+ computeRunValuesWithHarfbuzz(shaperItem, paint,
+ start, count, isRTL,
+ outAdvances, outTotalAdvance, outGlyphs);
} else {
+ int32_t end = start + count;
for (size_t i = 0; i < rc; ++i) {
int32_t startRun;
int32_t lengthRun;
UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
+ if (startRun >= end) {
+ continue;
+ }
+ int32_t endRun = startRun + lengthRun;
+ if (endRun <= start) {
+ continue;
+ }
+ if (startRun < start) {
+ startRun = start;
+ }
+ if (endRun > end) {
+ endRun = end;
+ }
+
+ lengthRun = endRun - startRun;
bool isRTL = (runDir == UBIDI_RTL);
jfloat runTotalAdvance = 0;
#if DEBUG_GLYPHS
LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d isRTL=%d",
startRun, lengthRun, isRTL);
#endif
- computeRunValuesWithHarfbuzz(paint, chars, startRun,
- lengthRun, contextCount, isRTL,
- outAdvances, &runTotalAdvance,
- outGlyphs, outLogClusters);
+ computeRunValuesWithHarfbuzz(shaperItem, paint,
+ startRun, lengthRun, isRTL,
+ outAdvances, &runTotalAdvance, outGlyphs);
*outTotalAdvance += runTotalAdvance;
}
@@ -464,12 +499,17 @@
bool isRTL = (bidiReq = 1) || (bidiReq = UBIDI_DEFAULT_RTL);
#if DEBUG_GLYPHS
LOGD("computeValuesWithHarfbuzz -- cannot run BiDi, considering a SINGLE Run "
- "-- run-start=%d run-len=%d isRTL=%d", 0, contextCount, isRTL);
+ "-- run-start=%d run-len=%d isRTL=%d", start, count, isRTL);
#endif
- computeRunValuesWithHarfbuzz(paint, chars, 0, contextCount, contextCount, isRTL,
- outAdvances, outTotalAdvance, outGlyphs, outLogClusters);
+ computeRunValuesWithHarfbuzz(shaperItem, paint,
+ start, count, isRTL,
+ outAdvances, outTotalAdvance, outGlyphs);
}
}
+
+ // Cleaning
+ freeShaperItem(shaperItem);
+
#if DEBUG_GLYPHS
LOGD("computeValuesWithHarfbuzz -- total-glyphs-count=%d", outGlyphs->size());
#endif
@@ -484,17 +524,12 @@
}
}
-void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
- size_t start, size_t count, size_t contextCount, bool isRTL,
+void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(HB_ShaperItem& shaperItem, SkPaint* paint,
+ size_t start, size_t count, bool isRTL,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
- Vector<jchar>* const outGlyphs, Vector<unsigned short>* const outLogClusters) {
+ Vector<jchar>* const outGlyphs) {
- HB_ShaperItem shaperItem;
- HB_FontRec font;
- FontData fontData;
-
- shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count,
- contextCount, isRTL);
+ shapeRun(shaperItem, start, count, isRTL);
#if DEBUG_GLYPHS
LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs,
@@ -511,10 +546,6 @@
#endif
outAdvances->insertAt(0, outAdvances->size(), count);
*outTotalAdvance = 0;
-
- // Cleaning
- deleteGlyphArrays(&shaperItem);
- HB_FreeFace(shaperItem.face);
return;
}
@@ -553,103 +584,21 @@
outGlyphs->add(glyph);
}
}
-
- // Get LogClusters
- if (outLogClusters) {
- size_t countLogClusters = outLogClusters->size();
- for (size_t i = 0; i < count; i++) {
- // As there may be successive runs, we need to shift the log clusters
- unsigned short logCluster = shaperItem.log_clusters[i] + countLogClusters;
-#if DEBUG_GLYPHS
- LOGD("HARFBUZZ -- logCluster[%d] relative=%d - absolute=%d", i, shaperItem.log_clusters[i], logCluster);
-#endif
- outLogClusters->add(logCluster);
- }
- }
-
- // Cleaning
- deleteGlyphArrays(&shaperItem);
- HB_FreeFace(shaperItem.face);
}
-void TextLayoutCacheValue::deleteGlyphArrays(HB_ShaperItem* shaperItem) {
- delete[] shaperItem->glyphs;
- delete[] shaperItem->attributes;
- delete[] shaperItem->advances;
- delete[] shaperItem->offsets;
+void TextLayoutCacheValue::deleteGlyphArrays(HB_ShaperItem& shaperItem) {
+ delete[] shaperItem.glyphs;
+ delete[] shaperItem.attributes;
+ delete[] shaperItem.advances;
+ delete[] shaperItem.offsets;
}
-void TextLayoutCacheValue::createGlyphArrays(HB_ShaperItem* shaperItem, int size) {
- shaperItem->glyphs = new HB_Glyph[size];
- shaperItem->attributes = new HB_GlyphAttributes[size];
- shaperItem->advances = new HB_Fixed[size];
- shaperItem->offsets = new HB_FixedPoint[size];
- shaperItem->num_glyphs = size;
-}
-
-void TextLayoutCacheValue::resetGlyphArrays(HB_ShaperItem* shaperItem) {
- int size = shaperItem->num_glyphs;
- // All the types here don't have pointers. It is safe to reset to
- // zero unless Harfbuzz breaks the compatibility in the future.
- memset(shaperItem->glyphs, 0, size * sizeof(shaperItem->glyphs[0]));
- memset(shaperItem->attributes, 0, size * sizeof(shaperItem->attributes[0]));
- memset(shaperItem->advances, 0, size * sizeof(shaperItem->advances[0]));
- memset(shaperItem->offsets, 0, size * sizeof(shaperItem->offsets[0]));
-}
-
-void TextLayoutCacheValue::getAdvances(size_t start, size_t count, jfloat* outAdvances) const {
- memcpy(outAdvances, mAdvances.array() + start, count * sizeof(jfloat));
-#if DEBUG_ADVANCES
- LOGD("getAdvances - start=%d count=%d", start, count);
- for (size_t i = 0; i < count; i++) {
- LOGD(" adv[%d] = %f", i, outAdvances[i]);
- }
-#endif
-}
-
-jfloat TextLayoutCacheValue::getTotalAdvance(size_t start, size_t count) const {
- jfloat outTotalAdvance = 0;
- for (size_t i = start; i < start + count; i++) {
- outTotalAdvance += mAdvances[i];
- }
-#if DEBUG_ADVANCES
- LOGD("getTotalAdvance - start=%d count=%d - total=%f", start, count, outTotalAdvance);
-#endif
- return outTotalAdvance;
-}
-
-void TextLayoutCacheValue::getGlyphsIndexAndCount(size_t start, size_t count, size_t* outStartIndex,
- size_t* outGlyphsCount) const {
- *outStartIndex = 0;
- if (count == 0) {
- *outGlyphsCount = 0;
- return;
- }
- *outStartIndex = mLogClusters[start];
- size_t endIndex = (start + count >= mAdvances.size()) ?
- mGlyphs.size() : mLogClusters[start + count];
- *outGlyphsCount = endIndex - *outStartIndex;
-#if DEBUG_GLYPHS
- LOGD("getGlyphsIndexes - start=%d count=%d - startIndex=%d count=%d", start, count,
- *outStartIndex, *outGlyphsCount);
- for(size_t i = 0; i < mGlyphs.size(); i++) {
- LOGD("getGlyphs - all - glyph[%d] = %d", i, mGlyphs[i]);
- }
- for(size_t i = 0; i < mAdvances.size(); i++) {
- LOGD("getGlyphs - all - logcl[%d] = %d", i, mLogClusters[i]);
- }
-#endif
-}
-
-const jchar* TextLayoutCacheValue::getGlyphs(size_t startIndex, size_t count) {
- const jchar* glyphs = mGlyphs.array() + startIndex;
-#if DEBUG_GLYPHS
- LOGD("getGlyphs - with startIndex = %d count = %d", startIndex, count);
- for (size_t i = 0; i < count; i++) {
- LOGD("getGlyphs - result - glyph[%d] = %d", i, glyphs[i]);
- }
-#endif
- return glyphs;
+void TextLayoutCacheValue::createGlyphArrays(HB_ShaperItem& shaperItem, int size) {
+ shaperItem.glyphs = new HB_Glyph[size];
+ shaperItem.attributes = new HB_GlyphAttributes[size];
+ shaperItem.advances = new HB_Fixed[size];
+ shaperItem.offsets = new HB_FixedPoint[size];
+ shaperItem.num_glyphs = size;
}
} // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 6dda1e5..580079d 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -68,7 +68,8 @@
public:
TextLayoutCacheKey();
- TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t count, int dirFlags);
+ TextLayoutCacheKey(const SkPaint* paint, const UChar* text, size_t start, size_t count,
+ size_t contextCount, int dirFlags);
TextLayoutCacheKey(const TextLayoutCacheKey& other);
@@ -88,7 +89,9 @@
private:
const UChar* text; // if text is NULL, use textCopy
String16 textCopy;
+ size_t start;
size_t count;
+ size_t contextCount;
int dirFlags;
SkTypeface* typeface;
SkScalar textSize;
@@ -119,32 +122,20 @@
void setElapsedTime(uint32_t time);
uint32_t getElapsedTime();
- void computeValues(SkPaint* paint, const UChar* chars, size_t contextCount, int dirFlags);
+ void computeValues(SkPaint* paint, const UChar* chars, size_t start, size_t count,
+ size_t contextCount, int dirFlags);
- void getAdvances(size_t start, size_t count, jfloat* outAdvances) const;
- jfloat getTotalAdvance(size_t start, size_t count) const;
- void getGlyphsIndexAndCount(size_t start, size_t count, size_t* outStartIndex,
- size_t* outGlyphsCount) const;
- const jchar* getGlyphs(size_t startIndex, size_t count);
+ inline const jfloat* getAdvances() const { return mAdvances.array(); }
+ inline size_t getAdvancesCount() const { return mAdvances.size(); }
+ inline jfloat getTotalAdvance() const { return mTotalAdvance; }
+ inline const jchar* getGlyphs() const { return mGlyphs.array(); }
+ inline size_t getGlyphsCount() const { return mGlyphs.size(); }
/**
* Get the size of the Cache entry
*/
size_t getSize();
- static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
- SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
- bool isRTL);
-
- static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
- SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
- bool isRTL);
-
- static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
- size_t contextCount, int dirFlags,
- Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
- Vector<jchar>* const outGlyphs, Vector<unsigned short>* const outLogClusters);
-
private:
/**
* Advances vector
@@ -162,23 +153,31 @@
Vector<jchar> mGlyphs;
/**
- * Harfbuzz Log Clusters
- */
- Vector<unsigned short> mLogClusters;
-
- /**
* Time for computing the values (in milliseconds)
*/
uint32_t mElapsedTime;
- static void deleteGlyphArrays(HB_ShaperItem* shaperItem);
- static void createGlyphArrays(HB_ShaperItem* shaperItem, int size);
- static void resetGlyphArrays(HB_ShaperItem* shaperItem);
-
- static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
- size_t count, size_t contextCount, bool isRTL,
+ static void computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
+ size_t start, size_t count, size_t contextCount, int dirFlags,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
- Vector<jchar>* const outGlyphs, Vector<unsigned short>* const outLogClusters);
+ Vector<jchar>* const outGlyphs);
+
+ static void computeRunValuesWithHarfbuzz(HB_ShaperItem& shaperItem, SkPaint* paint,
+ size_t start, size_t count, bool isRTL,
+ Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
+ Vector<jchar>* const outGlyphs);
+
+ static void initShaperItem(HB_ShaperItem& shaperItem, HB_FontRec* font, FontData* fontData,
+ SkPaint* paint, const UChar* chars, size_t contextCount);
+
+ static void freeShaperItem(HB_ShaperItem& shaperItem);
+
+ static void shapeRun(HB_ShaperItem& shaperItem, size_t start, size_t count, bool isRTL);
+
+ static void deleteGlyphArrays(HB_ShaperItem& shaperItem);
+
+ static void createGlyphArrays(HB_ShaperItem& shaperItem, int size);
+
}; // TextLayoutCacheValue
/**
@@ -202,8 +201,8 @@
*/
void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc);
- sp<TextLayoutCacheValue> getValue(SkPaint* paint, const jchar* text, jint count,
- jint dirFlags);
+ sp<TextLayoutCacheValue> getValue(SkPaint* paint, const jchar* text, jint start, jint count,
+ jint contextCount, jint dirFlags);
/**
* Clear the cache
@@ -256,6 +255,7 @@
* Dump Cache statistics
*/
void dumpCacheStats();
+
}; // TextLayoutCache
} // namespace android
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 14c6397..fe1aca0 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -147,8 +147,10 @@
field_slot_t* fieldSlot = window->getFieldSlotWithCheck(row, column);
if (!fieldSlot) {
- throwExceptionWithRowCol(env, row, column);
- return NULL;
+ // FIXME: This is really broken but we have CTS tests that depend
+ // on this legacy behavior.
+ //throwExceptionWithRowCol(env, row, column);
+ return FIELD_TYPE_NULL;
}
return fieldSlot->type;
}
@@ -203,8 +205,14 @@
if (type == FIELD_TYPE_STRING) {
uint32_t size = fieldSlot->data.buffer.size;
#if WINDOW_STORAGE_UTF8
- return size > 1 ? env->NewStringUTF(window->getFieldSlotValueString(fieldSlot))
- : gEmptyString;
+ if (size <= 1) {
+ return gEmptyString;
+ }
+ // Convert to UTF-16 here instead of calling NewStringUTF. NewStringUTF
+ // doesn't like UTF-8 strings with high codepoints. It actually expects
+ // Modified UTF-8 with encoded surrogate pairs.
+ String16 utf16(window->getFieldSlotValueString(fieldSlot), size - 1);
+ return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
#else
size_t chars = size / sizeof(char16_t);
return chars ? env->NewString(reinterpret_cast<jchar*>(
@@ -265,7 +273,7 @@
if (dataObj) {
if (size) {
jchar* data = static_cast<jchar*>(env->GetPrimitiveArrayCritical(dataObj, NULL));
- utf8_to_utf16(reinterpret_cast<const uint8_t*>(str), len,
+ utf8_to_utf16_no_null_terminator(reinterpret_cast<const uint8_t*>(str), len,
reinterpret_cast<char16_t*>(data));
env->ReleasePrimitiveArrayCritical(dataObj, data, 0);
}
diff --git a/core/jni/android_database_SQLiteQuery.cpp b/core/jni/android_database_SQLiteQuery.cpp
index fe62256..022a64c 100644
--- a/core/jni/android_database_SQLiteQuery.cpp
+++ b/core/jni/android_database_SQLiteQuery.cpp
@@ -35,99 +35,20 @@
namespace android {
-static jfieldID gHandleField;
-static jfieldID gStatementField;
-
-
-#define GET_STATEMENT(env, object) \
- (sqlite3_stmt *)env->GetIntField(object, gStatementField)
-#define GET_HANDLE(env, object) \
- (sqlite3 *)env->GetIntField(object, gHandleField)
-
-static int skip_rows(sqlite3_stmt *statement, int maxRows) {
- int retryCount = 0;
- for (int i = 0; i < maxRows; i++) {
- int err = sqlite3_step(statement);
- if (err == SQLITE_ROW){
- // do nothing
- } else if (err == SQLITE_DONE) {
- return i;
- } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
- // The table is locked, retry
- LOG_WINDOW("Database locked, retrying");
- if (retryCount > 50) {
- LOGE("Bailing on database busy rety");
- break;
- }
- // Sleep to give the thread holding the lock a chance to finish
- usleep(1000);
- retryCount++;
- continue;
- } else {
- return -1;
- }
- }
- LOG_WINDOW("skip_rows row %d", maxRows);
- return maxRows;
-}
-
-static int finish_program_and_get_row_count(sqlite3_stmt *statement) {
- int numRows = 0;
- int retryCount = 0;
- while (true) {
- int err = sqlite3_step(statement);
- if (err == SQLITE_ROW){
- numRows++;
- } else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {
- // The table is locked, retry
- LOG_WINDOW("Database locked, retrying");
- if (retryCount > 50) {
- LOGE("Bailing on database busy rety");
- break;
- }
- // Sleep to give the thread holding the lock a chance to finish
- usleep(1000);
- retryCount++;
- continue;
- } else {
- // no need to throw exception
- break;
- }
- }
- sqlite3_reset(statement);
- LOG_WINDOW("finish_program_and_get_row_count row %d", numRows);
- return numRows;
-}
-
-static jint native_fill_window(JNIEnv* env, jobject object, jint windowPtr,
- jint startPos, jint offsetParam, jint maxRead, jint lastPos)
-{
- int err;
- sqlite3_stmt * statement = GET_STATEMENT(env, object);
- int numRows = lastPos;
- maxRead += lastPos;
- int numColumns;
- int retryCount;
- int boundParams;
- CursorWindow * window;
- bool gotAllRows = true;
- bool gotException = false;
-
- if (statement == NULL) {
- LOGE("Invalid statement in fillWindow()");
- jniThrowException(env, "java/lang/IllegalStateException",
- "Attempting to access a deactivated, closed, or empty cursor");
- return 0;
- }
+static jint nativeFillWindow(JNIEnv* env, jclass clazz, jint databasePtr,
+ jint statementPtr, jint windowPtr, jint startPos, jint offsetParam) {
+ sqlite3* database = reinterpret_cast<sqlite3*>(databasePtr);
+ sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
+ CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
// Only do the binding if there is a valid offsetParam. If no binding needs to be done
- // offsetParam will be set to 0, an invliad value.
- if(offsetParam > 0) {
+ // offsetParam will be set to 0, an invalid value.
+ if (offsetParam > 0) {
// Bind the offset parameter, telling the program which row to start with
- err = sqlite3_bind_int(statement, offsetParam, startPos);
+ int err = sqlite3_bind_int(statement, offsetParam, startPos);
if (err != SQLITE_OK) {
LOGE("Unable to bind offset position, offsetParam = %d", offsetParam);
- throw_sqlite3_exception(env, GET_HANDLE(env, object));
+ throw_sqlite3_exception(env, database);
return 0;
}
LOG_WINDOW("Bound to startPos %d", startPos);
@@ -135,136 +56,123 @@
LOG_WINDOW("Not binding to startPos %d", startPos);
}
- // Get the native window
- window = reinterpret_cast<CursorWindow*>(windowPtr);
- if (!window) {
- LOGE("Invalid CursorWindow");
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "Bad CursorWindow");
- return 0;
- }
- LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d", window->getNumRows(), window->size(), window->freeSpace());
+ // We assume numRows is initially 0.
+ LOG_WINDOW("Window: numRows = %d, size = %d, freeSpace = %d",
+ window->getNumRows(), window->size(), window->freeSpace());
- numColumns = sqlite3_column_count(statement);
+ int numColumns = sqlite3_column_count(statement);
if (!window->setNumColumns(numColumns)) {
LOGE("Failed to change column count from %d to %d", window->getNumColumns(), numColumns);
jniThrowException(env, "java/lang/IllegalStateException", "numColumns mismatch");
return 0;
}
- retryCount = 0;
- if (startPos > 0) {
- int num = skip_rows(statement, startPos);
- if (num < 0) {
- throw_sqlite3_exception(env, GET_HANDLE(env, object));
- return 0;
- } else if (num < startPos) {
- LOGE("startPos %d > actual rows %d", startPos, num);
- return num;
- }
- }
-
- while(startPos != 0 || numRows < maxRead) {
- err = sqlite3_step(statement);
+ int retryCount = 0;
+ int totalRows = 0;
+ int addedRows = 0;
+ bool windowFull = false;
+ bool gotException = false;
+ const bool countAllRows = (startPos == 0); // when startPos is 0, we count all rows
+ while (!gotException && (!windowFull || countAllRows)) {
+ int err = sqlite3_step(statement);
if (err == SQLITE_ROW) {
- LOG_WINDOW("\nStepped statement %p to row %d", statement, startPos + numRows);
+ LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
retryCount = 0;
+ totalRows += 1;
- // Allocate a new field directory for the row. This pointer is not reused
- // since it mey be possible for it to be relocated on a call to alloc() when
- // the field data is being allocated.
- {
- field_slot_t * fieldDir = window->allocRow();
- if (!fieldDir) {
- LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d", startPos, numRows);
- gotAllRows = false;
- goto return_count;
- }
+ // Skip the row if the window is full or we haven't reached the start position yet.
+ if (startPos >= totalRows || windowFull) {
+ continue;
}
- // Pack the row into the window
- int i;
- for (i = 0; i < numColumns; i++) {
+ // Allocate a new field directory for the row. This pointer is not reused
+ // since it may be possible for it to be relocated on a call to alloc() when
+ // the field data is being allocated.
+ field_slot_t* fieldDir = window->allocRow();
+ if (!fieldDir) {
+ LOG_WINDOW("Failed allocating fieldDir at startPos %d row %d",
+ startPos, addedRows);
+ windowFull = true;
+ continue;
+ }
+
+ // Pack the row into the window.
+ for (int i = 0; i < numColumns; i++) {
int type = sqlite3_column_type(statement, i);
if (type == SQLITE_TEXT) {
// TEXT data
#if WINDOW_STORAGE_UTF8
- uint8_t const * text = (uint8_t const *)sqlite3_column_text(statement, i);
+ const uint8_t* text = reinterpret_cast<const uint8_t*>(
+ sqlite3_column_text(statement, i));
// SQLite does not include the NULL terminator in size, but does
// ensure all strings are NULL terminated, so increase size by
// one to make sure we store the terminator.
size_t size = sqlite3_column_bytes(statement, i) + 1;
#else
- uint8_t const * text = (uint8_t const *)sqlite3_column_text16(statement, i);
+ const uint8_t* text = reinterpret_cast<const uint8_t*>(
+ sqlite3_column_text16(statement, i));
size_t size = sqlite3_column_bytes16(statement, i);
#endif
int offset = window->alloc(size);
if (!offset) {
- window->freeLastRow();
LOG_WINDOW("Failed allocating %u bytes for text/blob at %d,%d", size,
- startPos + numRows, i);
- gotAllRows = false;
- goto return_count;
+ startPos + addedRows, i);
+ windowFull = true;
+ break;
}
-
window->copyIn(offset, text, size);
- // This must be updated after the call to alloc(), since that
- // may move the field around in the window
- field_slot_t * fieldSlot = window->getFieldSlot(numRows, i);
+ field_slot_t* fieldSlot = window->getFieldSlot(addedRows, i);
fieldSlot->type = FIELD_TYPE_STRING;
fieldSlot->data.buffer.offset = offset;
fieldSlot->data.buffer.size = size;
-
- LOG_WINDOW("%d,%d is TEXT with %u bytes", startPos + numRows, i, size);
+ LOG_WINDOW("%d,%d is TEXT with %u bytes", startPos + addedRows, i, size);
} else if (type == SQLITE_INTEGER) {
// INTEGER data
int64_t value = sqlite3_column_int64(statement, i);
- if (!window->putLong(numRows, i, value)) {
- window->freeLastRow();
+ if (!window->putLong(addedRows, i, value)) {
LOG_WINDOW("Failed allocating space for a long in column %d", i);
- gotAllRows = false;
- goto return_count;
+ windowFull = true;
+ break;
}
- LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + numRows, i, value);
+ LOG_WINDOW("%d,%d is INTEGER 0x%016llx", startPos + addedRows, i, value);
} else if (type == SQLITE_FLOAT) {
// FLOAT data
double value = sqlite3_column_double(statement, i);
- if (!window->putDouble(numRows, i, value)) {
- window->freeLastRow();
+ if (!window->putDouble(addedRows, i, value)) {
LOG_WINDOW("Failed allocating space for a double in column %d", i);
- gotAllRows = false;
- goto return_count;
+ windowFull = true;
+ break;
}
- LOG_WINDOW("%d,%d is FLOAT %lf", startPos + numRows, i, value);
+ LOG_WINDOW("%d,%d is FLOAT %lf", startPos + addedRows, i, value);
} else if (type == SQLITE_BLOB) {
// BLOB data
uint8_t const * blob = (uint8_t const *)sqlite3_column_blob(statement, i);
size_t size = sqlite3_column_bytes16(statement, i);
int offset = window->alloc(size);
if (!offset) {
- window->freeLastRow();
LOG_WINDOW("Failed allocating %u bytes for blob at %d,%d", size,
- startPos + numRows, i);
- gotAllRows = false;
- goto return_count;
+ startPos + addedRows, i);
+ windowFull = true;
+ break;
}
-
window->copyIn(offset, blob, size);
- // This must be updated after the call to alloc(), since that
- // may move the field around in the window
- field_slot_t * fieldSlot = window->getFieldSlot(numRows, i);
+ field_slot_t* fieldSlot = window->getFieldSlot(addedRows, i);
fieldSlot->type = FIELD_TYPE_BLOB;
fieldSlot->data.buffer.offset = offset;
fieldSlot->data.buffer.size = size;
-
- LOG_WINDOW("%d,%d is Blob with %u bytes @ %d", startPos + numRows, i, size, offset);
+ LOG_WINDOW("%d,%d is Blob with %u bytes @ %d",
+ startPos + addedRows, i, size, offset);
} else if (type == SQLITE_NULL) {
// NULL field
- window->putNull(numRows, i);
+ if (!window->putNull(addedRows, i)) {
+ LOG_WINDOW("Failed allocating space for a null in column %d", i);
+ windowFull = true;
+ break;
+ }
- LOG_WINDOW("%d,%d is NULL", startPos + numRows, i);
+ LOG_WINDOW("%d,%d is NULL", startPos + addedRows, i);
} else {
// Unknown data
LOGE("Unknown column type when filling database window");
@@ -274,14 +182,12 @@
}
}
- if (i < numColumns) {
- // Not all the fields fit in the window
- // Unknown data error happened
- break;
+ // Update the final row tally.
+ if (windowFull || gotException) {
+ window->freeLastRow();
+ } else {
+ addedRows += 1;
}
-
- // Mark the row as complete in the window
- numRows++;
} else if (err == SQLITE_DONE) {
// All rows processed, bail
LOG_WINDOW("Processed all rows");
@@ -290,63 +196,41 @@
// The table is locked, retry
LOG_WINDOW("Database locked, retrying");
if (retryCount > 50) {
- LOGE("Bailing on database busy rety");
- throw_sqlite3_exception(env, GET_HANDLE(env, object), "retrycount exceeded");
+ LOGE("Bailing on database busy retry");
+ throw_sqlite3_exception(env, database, "retrycount exceeded");
gotException = true;
- break;
+ } else {
+ // Sleep to give the thread holding the lock a chance to finish
+ usleep(1000);
+ retryCount++;
}
-
- // Sleep to give the thread holding the lock a chance to finish
- usleep(1000);
-
- retryCount++;
- continue;
} else {
- throw_sqlite3_exception(env, GET_HANDLE(env, object));
+ throw_sqlite3_exception(env, database);
gotException = true;
- break;
}
}
- LOG_WINDOW("Resetting statement %p after fetching %d rows in %d bytes\n\n\n\n", statement,
- numRows, window->size() - window->freeSpace());
- LOG_WINDOW("Filled window with %d rows in %d bytes", numRows,
- window->size() - window->freeSpace());
- if (err == SQLITE_ROW) {
- // there is more data to be returned. let the caller know by returning -1
- return -1;
+ LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows"
+ "to the window in %d bytes",
+ statement, totalRows, addedRows, window->size() - window->freeSpace());
+ sqlite3_reset(statement);
+
+ // Report the total number of rows on request.
+ if (startPos > totalRows) {
+ LOGE("startPos %d > actual rows %d", startPos, totalRows);
}
- return_count:
- if (startPos) {
- sqlite3_reset(statement);
- LOG_WINDOW("Not doing count(*) because startPos %d is non-zero", startPos);
- return 0;
- } else if (gotAllRows) {
- sqlite3_reset(statement);
- LOG_WINDOW("Not doing count(*) because we already know the count(*)");
- return numRows;
- } else if (gotException) {
- return 0;
- } else {
- // since startPos == 0, we need to get the count(*) of the result set
- return numRows + 1 + finish_program_and_get_row_count(statement);
- }
+ return countAllRows ? totalRows : 0;
}
-static jint native_column_count(JNIEnv* env, jobject object)
-{
- sqlite3_stmt * statement = GET_STATEMENT(env, object);
-
+static jint nativeColumnCount(JNIEnv* env, jclass clazz, jint statementPtr) {
+ sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
return sqlite3_column_count(statement);
}
-static jstring native_column_name(JNIEnv* env, jobject object, jint columnIndex)
-{
- sqlite3_stmt * statement = GET_STATEMENT(env, object);
- char const * name;
-
- name = sqlite3_column_name(statement, columnIndex);
-
+static jstring nativeColumnName(JNIEnv* env, jclass clazz, jint statementPtr,
+ jint columnIndex) {
+ sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
+ const char* name = sqlite3_column_name(statement, columnIndex);
return env->NewStringUTF(name);
}
@@ -354,30 +238,16 @@
static JNINativeMethod sMethods[] =
{
/* name, signature, funcPtr */
- {"native_fill_window", "(IIIII)I",
- (void *)native_fill_window},
- {"native_column_count", "()I", (void*)native_column_count},
- {"native_column_name", "(I)Ljava/lang/String;", (void *)native_column_name},
+ { "nativeFillWindow", "(IIIII)I",
+ (void*)nativeFillWindow },
+ { "nativeColumnCount", "(I)I",
+ (void*)nativeColumnCount},
+ { "nativeColumnName", "(II)Ljava/lang/String;",
+ (void*)nativeColumnName},
};
int register_android_database_SQLiteQuery(JNIEnv * env)
{
- jclass clazz;
-
- clazz = env->FindClass("android/database/sqlite/SQLiteQuery");
- if (clazz == NULL) {
- LOGE("Can't find android/database/sqlite/SQLiteQuery");
- return -1;
- }
-
- gHandleField = env->GetFieldID(clazz, "nHandle", "I");
- gStatementField = env->GetFieldID(clazz, "nStatement", "I");
-
- if (gHandleField == NULL || gStatementField == NULL) {
- LOGE("Error locating fields");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env,
"android/database/sqlite/SQLiteQuery", sMethods, NELEM(sMethods));
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e542a47..e79de2d 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -477,19 +477,17 @@
#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, text, count, flags);
+ value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
}
#else
value = new TextLayoutCacheValue();
- value->computeValues(paint, text, count, flags);
+ value->computeValues(paint, text, 0, count, count, flags);
#endif
- size_t startIndex = 0;
- size_t glyphsCount = 0;
- value->getGlyphsIndexAndCount(0, count, &startIndex, &glyphsCount);
- const jchar* glyphs = value->getGlyphs(startIndex, glyphsCount);
+ const jchar* glyphs = value->getGlyphs();
+ size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
#else
@@ -509,19 +507,17 @@
#if RTL_USE_HARFBUZZ
sp<TextLayoutCacheValue> value;
#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, text, contextCount, flags);
+ value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags);
if (value == NULL) {
LOGE("Cannot get TextLayoutCache value");
return ;
}
#else
value = new TextLayoutCacheValue();
- value->computeValues(paint, text, contextCount, flags);
+ value->computeValues(paint, text, start, count, contextCount, flags);
#endif
- size_t startIndex = 0;
- size_t glyphsCount = 0;
- value->getGlyphsIndexAndCount(start, count, &startIndex, &glyphsCount);
- const jchar* glyphs = value->getGlyphs(startIndex, glyphsCount);
+ const jchar* glyphs = value->getGlyphs();
+ size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
renderer->drawText((const char*) glyphs, bytesCount, glyphsCount, x, y, paint);
#else
diff --git a/core/res/res/layout/web_text_view_dropdown.xml b/core/res/res/layout/web_text_view_dropdown.xml
index 1dce5cb..1a6e9eb 100644
--- a/core/res/res/layout/web_text_view_dropdown.xml
+++ b/core/res/res/layout/web_text_view_dropdown.xml
@@ -23,4 +23,7 @@
android:background="#ffffffff"
android:singleLine="true"
android:layout_width="match_parent"
- android:layout_height="?android:attr/searchResultListItemHeight" />
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingTop="3dip"
+ android:paddingBottom="3dip" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a27abb3..6c7a981 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -158,6 +158,9 @@
<!-- The underline color and thickness for misspelled suggestion -->
<attr name="textAppearanceMisspelledSuggestion" format="reference" />
+ <!-- The underline color and thickness for auto correction suggestion -->
+ <attr name="textAppearanceAutoCorrectionSuggestion" format="reference" />
+
<!-- The underline color -->
<attr name="textUnderlineColor" format="reference|color" />
<!-- The underline thickness -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1f1dc26..20af731 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -257,6 +257,10 @@
<item name="android:textUnderlineColor">@color/holo_red_light</item>
</style>
+ <style name="TextAppearance.AutoCorrectionSuggestion" parent="TextAppearance.Suggestion">
+ <item name="android:textUnderlineColor">@color/holo_blue_light</item>
+ </style>
+
<!-- Widget Styles -->
<style name="Widget">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 1987d99..b18d88f 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -91,6 +91,7 @@
<item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item>
<item name="textAppearanceMisspelledSuggestion">@android:style/TextAppearance.MisspelledSuggestion</item>
+ <item name="textAppearanceAutoCorrectionSuggestion">@android:style/TextAppearance.AutoCorrectionSuggestion</item>
<item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
diff --git a/services/tests/servicestests/res/raw/net_dev_typical b/core/tests/coretests/res/raw/net_dev_typical
similarity index 100%
rename from services/tests/servicestests/res/raw/net_dev_typical
rename to core/tests/coretests/res/raw/net_dev_typical
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_extended b/core/tests/coretests/res/raw/xt_qtaguid_extended
similarity index 100%
rename from services/tests/servicestests/res/raw/xt_qtaguid_extended
rename to core/tests/coretests/res/raw/xt_qtaguid_extended
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_iface_typical b/core/tests/coretests/res/raw/xt_qtaguid_iface_typical
similarity index 99%
rename from services/tests/servicestests/res/raw/xt_qtaguid_iface_typical
rename to core/tests/coretests/res/raw/xt_qtaguid_iface_typical
index efa4cd5..610723a 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_iface_typical
+++ b/core/tests/coretests/res/raw/xt_qtaguid_iface_typical
@@ -1,6 +1,6 @@
-rmnet3 1 0 0 0 0 20822 501 1149991 815
-rmnet2 1 0 0 0 0 1594 15 1313 15
-rmnet1 1 0 0 0 0 207398 458 166918 565
-rmnet0 1 0 0 0 0 2112 24 700 10
-test1 1 1 2 3 4 5 6 7 8
-test2 0 1 2 3 4 5 6 7 8
+rmnet3 1 0 0 0 0 20822 501 1149991 815
+rmnet2 1 0 0 0 0 1594 15 1313 15
+rmnet1 1 0 0 0 0 207398 458 166918 565
+rmnet0 1 0 0 0 0 2112 24 700 10
+test1 1 1 2 3 4 5 6 7 8
+test2 0 1 2 3 4 5 6 7 8
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical b/core/tests/coretests/res/raw/xt_qtaguid_typical
similarity index 100%
rename from services/tests/servicestests/res/raw/xt_qtaguid_typical
rename to core/tests/coretests/res/raw/xt_qtaguid_typical
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set b/core/tests/coretests/res/raw/xt_qtaguid_typical_with_set
similarity index 99%
rename from services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
rename to core/tests/coretests/res/raw/xt_qtaguid_typical_with_set
index f9f34ac..b302bb7 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
+++ b/core/tests/coretests/res/raw/xt_qtaguid_typical_with_set
@@ -1,13 +1,13 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_packets rx_tcp_bytes rx_udp_packets rx_udp_bytes rx_other_packets rx_other_bytes tx_tcp_packets tx_tcp_bytes tx_udp_packets tx_udp_bytes tx_other_packets tx_other_bytes
-2 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0
-3 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0
-5 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0
-6 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0
-7 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-8 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0
-9 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0
-11 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-12 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0
-13 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_packets rx_tcp_bytes rx_udp_packets rx_udp_bytes rx_other_packets rx_other_bytes tx_tcp_packets tx_tcp_bytes tx_udp_packets tx_udp_bytes tx_other_packets tx_other_bytes
+2 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0
+3 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+4 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0
+5 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0
+6 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0
+7 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+8 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0
+9 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+10 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0
+11 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+12 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0
+13 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/core/tests/coretests/src/android/database/DatabaseCursorTest.java b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
index d5b9ee6..179338d 100644
--- a/core/tests/coretests/src/android/database/DatabaseCursorTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseCursorTest.java
@@ -290,110 +290,7 @@
public void onInvalidated() {
}
}
-
- //@Large
- @Suppress
- public void testLoadingThreadDelayRegisterData() throws Exception {
- mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
-
- final int count = 505;
- String sql = "INSERT INTO test (data) VALUES (?);";
- SQLiteStatement s = mDatabase.compileStatement(sql);
- for (int i = 0; i < count; i++) {
- s.bindLong(1, i);
- s.execute();
- }
- int maxRead = 500;
- int initialRead = 5;
- SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
- null, initialRead, maxRead);
-
- TestObserver observer = new TestObserver(count, c);
- c.getCount();
- c.registerDataSetObserver(observer);
- if (!observer.quit) {
- Looper.loop();
- }
- c.close();
- }
-
- //@LargeTest
- @BrokenTest("Consistently times out")
- @Suppress
- public void testLoadingThread() throws Exception {
- mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
-
- final int count = 50000;
- String sql = "INSERT INTO test (data) VALUES (?);";
- SQLiteStatement s = mDatabase.compileStatement(sql);
- for (int i = 0; i < count; i++) {
- s.bindLong(1, i);
- s.execute();
- }
-
- int maxRead = 1000;
- int initialRead = 5;
- SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
- null, initialRead, maxRead);
-
- TestObserver observer = new TestObserver(count, c);
- c.registerDataSetObserver(observer);
- c.getCount();
-
- Looper.loop();
- c.close();
- }
-
- //@LargeTest
- @BrokenTest("Consistently times out")
- @Suppress
- public void testLoadingThreadClose() throws Exception {
- mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
-
- final int count = 1000;
- String sql = "INSERT INTO test (data) VALUES (?);";
- SQLiteStatement s = mDatabase.compileStatement(sql);
- for (int i = 0; i < count; i++) {
- s.bindLong(1, i);
- s.execute();
- }
-
- int maxRead = 11;
- int initialRead = 5;
- SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
- null, initialRead, maxRead);
-
- TestObserver observer = new TestObserver(count, c);
- c.registerDataSetObserver(observer);
- c.getCount();
- c.close();
- }
-
- @LargeTest
- public void testLoadingThreadDeactivate() throws Exception {
- mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
-
- final int count = 1000;
- String sql = "INSERT INTO test (data) VALUES (?);";
- SQLiteStatement s = mDatabase.compileStatement(sql);
- for (int i = 0; i < count; i++) {
- s.bindLong(1, i);
- s.execute();
- }
-
- int maxRead = 11;
- int initialRead = 5;
- SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
- null, initialRead, maxRead);
-
- TestObserver observer = new TestObserver(count, c);
- c.registerDataSetObserver(observer);
- c.getCount();
- c.deactivate();
- c.close();
- }
-
@LargeTest
public void testManyRowsLong() throws Exception {
mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index d78d2ef..7082deb 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -25,8 +25,12 @@
import android.test.suitebuilder.annotation.SmallTest;
+import com.google.android.collect.Sets;
+
import junit.framework.TestCase;
+import java.util.HashSet;
+
@SmallTest
public class NetworkStatsTest extends TestCase {
@@ -233,13 +237,43 @@
assertValues(first, 2, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
}
+ public void testGetTotal() {
+ final NetworkStats stats = new NetworkStats(TEST_START, 3)
+ .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 64L, 4L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L);
+
+ assertValues(stats.getTotal(null), 1280L, 80L, 0L, 2L, 20L);
+ assertValues(stats.getTotal(null, 100), 1152L, 72L, 0L, 2L, 20L);
+ assertValues(stats.getTotal(null, 101), 128L, 8L, 0L, 0L, 0L);
+
+ final HashSet<String> ifaces = Sets.newHashSet();
+ assertValues(stats.getTotal(null, ifaces), 0L, 0L, 0L, 0L, 0L);
+
+ ifaces.add(TEST_IFACE2);
+ assertValues(stats.getTotal(null, ifaces), 1024L, 64L, 0L, 0L, 0L);
+ }
+
private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
final NetworkStats.Entry entry = stats.getValues(index, null);
+ assertValues(entry, iface, uid, set, tag);
+ assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations);
+ }
+
+ private static void assertValues(
+ NetworkStats.Entry entry, String iface, int uid, int set, int tag) {
assertEquals(iface, entry.iface);
assertEquals(uid, entry.uid);
assertEquals(set, entry.set);
assertEquals(tag, entry.tag);
+ }
+
+ private static void assertValues(NetworkStats.Entry entry, long rxBytes, long rxPackets,
+ long txBytes, long txPackets, long operations) {
assertEquals(rxBytes, entry.rxBytes);
assertEquals(rxPackets, entry.rxPackets);
assertEquals(txBytes, entry.txBytes);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
similarity index 89%
rename from services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
rename to core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
index 40640e0..8a64f2b 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.internal.net;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
@@ -25,9 +25,8 @@
import android.content.res.Resources;
import android.net.NetworkStats;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.frameworks.servicestests.R;
+import com.android.frameworks.coretests.R;
import java.io.File;
import java.io.FileOutputStream;
@@ -39,12 +38,11 @@
import libcore.io.Streams;
/**
- * Tests for {@link NetworkManagementService}.
+ * Tests for {@link NetworkStatsFactory}.
*/
-@LargeTest
-public class NetworkManagementServiceTest extends AndroidTestCase {
+public class NetworkStatsFactoryTest extends AndroidTestCase {
private File mTestProc;
- private NetworkManagementService mService;
+ private NetworkStatsFactory mFactory;
@Override
public void setUp() throws Exception {
@@ -55,12 +53,12 @@
IoUtils.deleteContents(mTestProc);
}
- mService = NetworkManagementService.createForTest(mContext, mTestProc, true);
+ mFactory = new NetworkStatsFactory(mTestProc);
}
@Override
public void tearDown() throws Exception {
- mService = null;
+ mFactory = null;
if (mTestProc.exists()) {
IoUtils.deleteContents(mTestProc);
@@ -72,7 +70,7 @@
public void testNetworkStatsDetail() throws Exception {
stageFile(R.raw.xt_qtaguid_typical, new File(mTestProc, "net/xt_qtaguid/stats"));
- final NetworkStats stats = mService.getNetworkStatsDetail();
+ final NetworkStats stats = mFactory.readNetworkStatsDetail();
assertEquals(31, stats.size());
assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0, 14615L, 4270L);
assertStatsEntry(stats, "wlan0", 10004, SET_DEFAULT, 0, 333821L, 53558L);
@@ -84,7 +82,7 @@
public void testNetworkStatsDetailExtended() throws Exception {
stageFile(R.raw.xt_qtaguid_extended, new File(mTestProc, "net/xt_qtaguid/stats"));
- final NetworkStats stats = mService.getNetworkStatsDetail();
+ final NetworkStats stats = mFactory.readNetworkStatsDetail();
assertEquals(2, stats.size());
assertStatsEntry(stats, "test0", 1000, SET_DEFAULT, 0, 1024L, 2048L);
assertStatsEntry(stats, "test0", 1000, SET_DEFAULT, 0xF00D, 512L, 512L);
@@ -93,7 +91,7 @@
public void testNetworkStatsSummary() throws Exception {
stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
- final NetworkStats stats = mService.getNetworkStatsSummary();
+ final NetworkStats stats = mFactory.readNetworkStatsSummary();
assertEquals(6, stats.size());
assertStatsEntry(stats, "lo", UID_ALL, SET_DEFAULT, TAG_NONE, 8308L, 8308L);
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_DEFAULT, TAG_NONE, 1507570L, 489339L);
@@ -111,7 +109,7 @@
stageLong(2048L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_bytes"));
stageLong(256L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_packets"));
- final NetworkStats stats = mService.getNetworkStatsSummary();
+ final NetworkStats stats = mFactory.readNetworkStatsSummary();
assertEquals(7, stats.size());
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_DEFAULT, TAG_NONE, 1507570L, 489339L);
assertStatsEntry(stats, "wlan0", UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 2048L);
@@ -125,7 +123,7 @@
stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
stageLong(40L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_packets"));
- final NetworkStats stats = mService.getNetworkStatsSummary();
+ final NetworkStats stats = mFactory.readNetworkStatsSummary();
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_DEFAULT, TAG_NONE, 1507570L + 10L,
2205L + 20L, 489339L + 30L, 2237L + 40L);
}
@@ -138,7 +136,7 @@
stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
stageLong(40L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_packets"));
- final NetworkStats stats = mService.getNetworkStatsSummary();
+ final NetworkStats stats = mFactory.readNetworkStatsSummary();
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_DEFAULT, TAG_NONE, 10L, 20L, 30L, 40L);
}
@@ -153,7 +151,7 @@
public void testNetworkStatsWithSet() throws Exception {
stageFile(R.raw.xt_qtaguid_typical_with_set, new File(mTestProc, "net/xt_qtaguid/stats"));
- final NetworkStats stats = mService.getNetworkStatsDetail();
+ final NetworkStats stats = mFactory.readNetworkStatsDetail();
assertEquals(12, stats.size());
assertStatsEntry(stats, "rmnet0", 1000, SET_DEFAULT, 0, 278102L, 253L, 10487L, 182L);
assertStatsEntry(stats, "rmnet0", 1000, SET_FOREGROUND, 0, 26033L, 30L, 1401L, 26L);
@@ -162,7 +160,7 @@
public void testNetworkStatsSingle() throws Exception {
stageFile(R.raw.xt_qtaguid_iface_typical, new File(mTestProc, "net/xt_qtaguid/iface_stat_all"));
- final NetworkStats stats = mService.getNetworkStatsSummary();
+ final NetworkStats stats = mFactory.readNetworkStatsSummary();
assertEquals(6, stats.size());
assertStatsEntry(stats, "rmnet0", UID_ALL, SET_DEFAULT, TAG_NONE, 2112L, 24L, 700L, 10L);
assertStatsEntry(stats, "test1", UID_ALL, SET_DEFAULT, TAG_NONE, 6L, 8L, 10L, 12L);
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 1e3e275..18d9a48 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -693,17 +693,20 @@
<ul>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/icon_design.html">
- <span class="en">Icon Design</span>
+ <span class="en">Icon Design <span class="new">updated</span></span>
</a></div>
<ul>
<li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/icon_design_launcher.html">
- <span class="en">Launcher Icons</span>
+ <span class="en">Launcher Icons <span class="new">updated</span></span>
</a></li>
<li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/icon_design_menu.html">
<span class="en">Menu Icons</span>
</a></li>
+ <li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/icon_design_action_bar.html">
+ <span class="en">Action Bar Icons <span class="new">new!</span></span>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/icon_design_status_bar.html">
- <span class="en">Status Bar Icons</span>
+ <span class="en">Status Bar Icons <span class="new">updated</span></span>
</a></li>
<li><a href="<?cs var:toroot ?>guide/practices/ui_guidelines/icon_design_tab.html">
<span class="en">Tab Icons</span>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design.jd b/docs/html/guide/practices/ui_guidelines/icon_design.jd
index d3b702d..07b73bb 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design.jd
@@ -36,6 +36,8 @@
<h2>Downloads</h2>
<ol>
+<li><a href="{@docRoot}shareables/icon_templates-v4.0.zip">Android Icon
+Templates Pack, v4.0 »</a></li>
<li><a href="{@docRoot}shareables/icon_templates-v2.3.zip">Android Icon
Templates Pack, v2.3 »</a></li>
<li><a href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon
@@ -74,6 +76,10 @@
<dt><strong><a href="icon_design_menu.html">Menu Icons</a></strong></dt>
<dd>Menu icons are graphical elements placed in the options menu shown to
users when they press the Menu button.</dd>
+ <dt><strong><a href="icon_design_action_bar.html">Action Bar Icons</a>
+ <span class="new">new!</span></strong></dt>
+ <dd>Action Bar icons are graphical elements representing action items in the
+ <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>.</dd>
<dt><strong><a href="icon_design_status_bar.html">Status Bar Icons</a></strong></dt>
<dd>Status bar icons are used to represent notifications from your
application in the status bar.</dd>
@@ -112,8 +118,8 @@
</p>
<p style="margin-left:2em"><a
-href="{@docRoot}shareables/icon_templates-v2.3.zip">Download the Icon Templates
-Pack for Android 2.3 »</a>
+href="{@docRoot}shareables/icon_templates-v4.0.zip">Download the Icon Templates
+Pack for Android 4.0 »</a>
<p>For previous versions of the Icon Templates Pack, see the <em>Downloads</em>
section in the box at the top-right corner of this page.</p>
@@ -134,7 +140,7 @@
regardless of the device's screen size or resolution.</p>
<p>In general, the recommended approach is to create a separate set of icons for
-each of the three generalized screen densities listed in Table 1. Then,
+each generalized screen density. Then,
store them in density-specific resource directories in your application. When
your application runs, the Android platform will check the characteristics of
the device screen and load icons from the appropriate density-specific
@@ -146,145 +152,6 @@
<p>For tips on how to create and manage icon sets for multiple densities, see
<a href="#design-tips">Tips for Designers</a>.</p>
-<p class="table-caption" id="screens-table"><strong>Table 1.</strong> Summary of
-finished icon dimensions for each of the three generalized screen densities, by
-icon type.</p>
-
- <table>
- <tbody>
-<tr>
-<th>Icon Type</th><th colspan="3">Standard Asset Sizes (in Pixels), for
-Generalized Screen Densities</th></tr>
- <tr>
- <td style="background-color:#f3f3f3"></td>
- <th style="background-color:#f3f3f3;font-weight:normal">
- <nobr>Low density screen <em>(ldpi)</em></nobr>
- </th>
- <th style="background-color:#f3f3f3;font-weight:normal">
- <nobr>Medium density screen <em>(mdpi)</em></nobr>
- </th>
- <th style="background-color:#f3f3f3;font-weight:normal">
- <nobr>High density screen <em>(hdpi)</em><nobr>
- </th>
- </tr>
-
- <tr>
- <th style="background-color:#f3f3f3;font-weight:normal">
- Launcher
- </th>
- <td>
- 36 x 36 px
- </td>
-
- <td>
- 48 x 48 px
- </td>
- <td>
- 72 x 72 px
- </td>
- </tr>
-
- <tr>
- <th style="background-color:#f3f3f3;font-weight:normal">
- Menu
- </th>
- <td>
- 36 x 36 px
- </td>
-
- <td>
- 48 x 48 px
- </td>
- <td>
- 72 x 72 px
- </td>
- </tr>
-
- <tr>
- <th style="background-color:#f3f3f3;font-weight:normal">
- Status Bar (Android 2.3 and later)
- </th>
- <td>
- 12w x 19h px<br>
- (preferred, width may vary)
- </td>
-
- <td>
- 16w x 25h px<br>
- (preferred, width may vary)
- </td>
- <td>
- 24w x 38h px<br>
- (preferred, width may vary)
- </td>
- </tr>
-
- <tr>
- <th style="background-color:#f3f3f3;font-weight:normal">
- Status Bar (Android 2.2 and below)
- </th>
- <td>
- 19 x 19 px
- </td>
-
- <td>
- 25 x 25 px
- </td>
- <td>
- 38 x 38 px
- </td>
- </tr>
-
- <tr>
- <th style="background-color:#f3f3f3;font-weight:normal">
- Tab
- </th>
- <td>
- 24 x 24 px
- </td>
-
- <td>
- 32 x 32 px
- </td>
- <td>
- 48 x 48 px
- </td>
- </tr>
-
- <tr>
- <th style="background-color:#f3f3f3;font-weight:normal">
- Dialog
- </th>
- <td>
- 24 x 24 px
- </td>
-
- <td>
- 32 x 32 px
- </td>
- <td>
- 48 x 48 px
- </td>
- </tr>
-
- <tr>
- <th style="background-color:#f3f3f3;font-weight:normal">
- List View
- </th>
- <td>
- 24 x 24 px
- </td>
-
- <td>
- 32 x 32 px
- </td>
- <td>
- 48 x 48 px
- </td>
- </tr>
- </tbody>
- </table>
-
@@ -317,7 +184,7 @@
<td><code>ic_launcher_calendar.png</code></td>
</tr>
<tr>
-<td>Menu icons</td>
+<td>Menu icons and Action Bar icons</td>
<td><code>ic_menu</code></td>
<td><code>ic_menu_archive.png</code></td>
</tr>
@@ -349,7 +216,7 @@
find, we recommend creating a directory structure in your working space that
organizes asset files per resolution. For example:</p>
-<pre>assets/...
+<pre>art/...
ldpi/...
_pre_production/...
<em>working_file</em>.psd
@@ -361,6 +228,10 @@
hdpi/...
_pre_production/...
<em>working_file</em>.psd
+ <em>finished_asset</em>.png
+ xhdpi/...
+ _pre_production/...
+ <em>working_file</em>.psd
<em>finished_asset</em>.png</pre>
<p>This structure parallels the density-specific structure in which you will
@@ -380,6 +251,8 @@
drawable-mdpi/...
<em>finished_asset</em>.png
drawable-hdpi/...
+ <em>finished_asset</em>.png
+ drawable-xhdpi/...
<em>finished_asset</em>.png</pre>
@@ -398,25 +271,16 @@
<h3>Start with large artboards</h3>
-<p>Because you will need to create assets for different screen densities, as
-shown in <a href="#screens-table">Table 1</a>, it is best to start your icon
+<p>Because you will need to create assets for different screen densities,
+it is best to start your icon
designs on large artboards with dimensions that are multiples of the target icon
sizes. For example, <a
href="{@docRoot}guide/practices/ui_guidelines/icon_design_launcher.html">launcher
-icons</a> are 72, 48, or 36 pixels wide, depending on screen density. If you
+icons</a> are 96, 72, 48, or 36 pixels wide, depending on screen density. If you
initially draw launcher icons on an 864x864 artboard, it will be easier and
cleaner to tweak the icons when you scale the artboard down to the target
sizes for final asset creation.</p>
-<p>It's also beneficial to add guide lines (also known as guides) to your large
-artboard for the recommended safe margins at the highest target density.
-Continuing with the example above, per the <a
-href="{@docRoot}guide/practices/ui_guidelines/icon_design_launcher.html#size5">guidelines</a>,
-launcher icon content should be 60x60 pixels (56x56 for square icons) within the
-full 72x72 asset, or a safe margin of 6 pixels on each side. On an 864x864
-artboard, this corresponds to horizontal and vertical guide lines 72 pixels from
-each side of the artboard.</p>
-
<h3>When scaling, redraw bitmap layers as needed</h3>
@@ -431,22 +295,12 @@
<h3>When saving image assets, remove unnecessary metadata</h3>
-<p>To help keep each image asset as small as possible, make sure to remove any
-unnecessary headers from the file, such as Adobe Fireworks metadata or Adobe
-Photoshop headers. To remove the Photoshop header, follow these steps: </p>
-
-<ol>
-<li>Under the <strong>File</strong> menu, choose the <strong>Save for Web &
-Devices</strong> command </li>
-<li>On the "Save for Web & Devices" panel, set the Preset pop-up to
-"PNG-24," set the pop-up under Presets to "PNG-24" as well, and select the
-Transparency box (if the image uses transparency)</li>
-<li>Select <strong>Save</strong>.</li>
-</ol>
-
-<p>It is also useful to use PNG file size optimization tools such as <a
+<p>Although the Android SDK tools will automatically compress PNGs when packaging
+application resources into the application binary, a good practice is to remove
+unnecessary headers and metadata from your PNG assets. Tools such as <a
href="http://optipng.sourceforge.net/">OptiPNG</a> or <a
-href="http://pmt.sourceforge.net/pngcrush/">Pngcrush</a>.
+href="http://pmt.sourceforge.net/pngcrush/">Pngcrush</a> can ensure that this
+metadata is removed and that your image asset file sizes are optimized.</p>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_action_bar.jd b/docs/html/guide/practices/ui_guidelines/icon_design_action_bar.jd
new file mode 100644
index 0000000..449c27f
--- /dev/null
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_action_bar.jd
@@ -0,0 +1,189 @@
+page.title=Action Bar Icons
+parent.title=Icon Design Guidelines
+parent.link=icon_design.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+<ol>
+<li><a href="#icon11">Android 3.0 and Later</a>
+ <ol>
+ <li><a href="#size11">Size and format</a></li>
+ <li><a href="#style11">Style, colors, and effects</a></li>
+ <li><a href="#examples11">Example icons</a></li>
+ </ol>
+</li>
+</ol>
+
+<h2>See also</h2>
+
+<ol>
+<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a></li>
+<li><a href="{@docRoot}guide/topics/ui/actionbar.html">Using the Action Bar</a></li>
+</ol>
+
+</div>
+</div>
+
+
+
+<p>Action Bar icons are graphical elements placed in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> representing individual action
+items.</p>
+
+<p>As described in <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#icon-sets">Providing Density-Specific
+Icon Sets</a> and <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a>, you should create separate icons for all generalized screen densities, including low-,
+medium-, high-, and extra-high-density screens. This ensures that your icons will display properly
+across the range of devices on which your application can be installed. See <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#design-tips">Tips for Designers</a>
+for suggestions on how to work with multiple sets of icons.</p>
+
+<p><strong>Final art must be exported as a transparent PNG file. Do not include
+a background color</strong>.</p>
+
+<p>Templates for creating icons in Adobe Photoshop are available in the <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#templatespack">Icon
+Templates Pack</a>.</p>
+
+
+
+<h2 id="icon11">Android 3.0 and Later</h2>
+
+<p>The following guidelines describe how to design action bar icons for Android
+3.0 (API Level 11) and later.</p>
+
+
+<h3 id="size11">Size and format</h2>
+
+<p>Action Bar icons should be 32-bit PNGs with an alpha channel for transparency. The finished
+action bar icon dimensions, corresponding to a given generalized screen density, are shown in
+the table below.</p>
+
+<p class="table-caption" id="screens_table"><strong>Table 1.</strong> Summary of
+finished Action Bar icon dimensions for each generalized screen density.</p>
+
+<table>
+ <tbody>
+ <tr>
+ <th></th>
+ <th>
+ <code>ldpi</code> (120 dpi)<br>
+ <small style="font-weight: normal">(Low density screen)</small>
+ </th>
+ <th>
+ <code>mdpi</code> (160 dpi)<br>
+ <small style="font-weight: normal">(Medium density screen)</small>
+ </th>
+ <th>
+ <code>hdpi</code> (240 dpi)<br>
+ <small style="font-weight: normal">(High density screen)</small>
+ </th>
+ <th>
+ <code>xhdpi</code> (320 dpi)<br>
+ <small style="font-weight: normal">(Extra-high density screen)</small>
+ </th>
+ </tr>
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Action Bar Icon Size
+ </th>
+ <td>
+ 18 x 18 px
+ </td>
+ <td>
+ 24 x 24 px
+ </td>
+ <td>
+ 36 x 36 px
+ </td>
+ <td>
+ 48 x 48 px
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+
+
+<h3 id="style11">Style, colors, and effects</h3>
+
+<p>Action Bar icons are flat, pictured face on, and generally greyscale, depending on the
+application's theme. Action Bar icons should not look three-dimensional.</p>
+
+<p>In order to maintain consistency across the application's Action Bar, all Action Bar icons should
+use the same color palette and effects.</p>
+
+<p>When using the default "Holo Light" or "Holo Dark" themes, icons should use the color palette
+and effects shown in Figure 1 and Figure 2, below.</p>
+
+
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/action_bar_holo_light_style.png"
+ alt="A view of effects for Action Bar icons for the 'Holo Light' theme.">
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 1. </strong>Style and effects for "Holo Light" theme Action Bar icons.</p>
+ <div class="image-caption-nested">
+ <table>
+ <tr><td><em>1.</em></td><td nowrap>Fill color:</td><td><code>#333333</code>, 60% opacity
+ <br><br></td></tr>
+ <tr><td><em>2.</em></td><td nowrap>Inner content:</td><td>Inner content should subtract from
+ the outer shape and consist purely of transparent pixels.</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/action_bar_holo_dark_style.png"
+ alt="A view of effects for Action Bar icons for the 'Holo Dark' theme.">
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 2. </strong>Style and effects for "Holo Dark" theme Action Bar icons.</p>
+ <div class="image-caption-nested">
+ <table>
+ <tr><td><em>1.</em></td><td nowrap>Fill color:</td><td><code>#ffffff</code>, 80% opacity
+ <br><br></td></tr>
+ <tr><td><em>2.</em></td><td nowrap>Inner content:</td><td>Inner content should subtract from
+ the outer shape and consist purely of transparent pixels.</td></tr>
+ </table>
+ <p class="note"><strong>Note: </strong> icons should should have a transparent background;
+ the dark background here is for effect only.</p>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+
+
+
+<h3 id="examples11">Example icons</h3>
+
+<p>Shown below are example extra-high-density Action Bar icons that are used throughout Android
+system applications.</p>
+
+<p class="warning"><strong>Warning:</strong> Because resources can change between platform versions,
+you should not reference built-in icons using the Android platform resource IDs (i.e. menu or Action
+Bar icons under <code>android.R.drawable</code>). If you want to use any icons or other internal
+drawable resources, you should store a local copy of those icons or drawables in your application
+resources, then reference the local copy from your application code. In that way, you can maintain
+control over the appearance of your icons, even if the system's copy changes. Note that the grid
+below is not intended to be complete.</p>
+
+<img src="{@docRoot}images/icon_design/action_bar_examples.png" />
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd b/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
index cb04b55..3f6061c 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_launcher.jd
@@ -9,23 +9,15 @@
<h2>In this document</h2>
<ol>
-<li><a href="#market">Application Icons in Android Market</a></li>
-<li><a href="#icon5">Android 2.0 and Later</a>
- <ol>
- <li><a href="#style5">Style</a></li>
- <li><a href="#size5">Size</a></li>
- <li><a href="#materialscolors5">Materials and colors</a></li>
- <li><a href="#effects5">Effects</a></li>
- <li><a href="#dodonts5">Do's and don'ts</a></li>
- <li><a href="#examples5">Example icons</a></li>
- </ol>
-</li>
-<li><a href="#icon1">Android 1.6 and Earlier</a></li>
+<li><a href="#goals">Goals of the Launcher Icon</a></li>
+<li><a href="#dos_donts">Do's and Don'ts</a></li>
+<li><a href="#size">Size and Format</a></li>
</ol>
<h2>See also</h2>
<ol>
+<li><a href="icon_design_launcher_archive.html">Older guidelines</a></li>
<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
Screens</a></li>
</ol>
@@ -34,487 +26,225 @@
</div>
-<p>A Launcher icon is a graphic that represents your application on the device's
-Home screen and in the Launcher window.</p>
+<p>A launcher icon is a graphic that represents your application. Launcher icons are used by
+Launcher applications and appear on the user’s Home screen. Launcher icons can also be used to
+represent shortcuts into your application (for example, a contact shortcut icon that opens detail
+information for a contact).</p>
-<p>The user opens the Launcher by touching the icon at the bottom of the Home
-screen. The Launcher opens and exposes the icons for all of the installed
-applications. The user selects an application and opens it by touching the
-Launcher icon or by means of any hardware navigation controls available, such as
-a trackball or d-pad.</p>
+<p>As described in <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#icon-sets">Providing Density-Specific
+Icon Sets</a> and <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a>, you should create separate icons for all generalized screen densities, including low-,
+medium-, high-, and extra-high-density screens. This ensures that your icons will display properly
+across the range of devices on which your application can be installed. See <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#design-tips">Tips for Designers</a>
+for suggestions on how to work with multiple sets of icons.</p>
-<p>As described in <a href="icon_design.html#icon-sets">Providing
-Density-Specific Icon Sets</a>, you should create separate icons for low-,
-medium-, and high-density screens. This ensures that your icons will display
-properly across the range of devices on which your application can be installed.
-See <a href="icon_design.html#design-tips">Tips for Designers</a> for
-suggestions on how to work with multiple sets of icons.</p>
+<p>A high-resolution version of your application launcher icon is also required by Android Market
+for use in application listings. For more details on this, see <a
+href="#icons_in_market">Application Icons in Android Market</a> below.</p>
+<p class="note"><strong>Note:</strong>
-<h2 id="market">Application Icons in Android Market</h2>
+The launcher icon guidelines pertaining to all versions of Android have been re-written. If you
+need to review the old guidelines, see the
+<a href="icon_design_launcher_archive.html">launcher icon guidelines archive</a>.
-<p>If you are <a href="{@docRoot}guide/publishing/publishing.html">publishing
-your application on Android Market</a>, you will also need to provide a 512x512
-pixel, high-resolution application icon in the <a
-href="http://market.android.com/publish">developer console</a> at upload-time.
-This icon will be used in various locations in Android Market and does
-not replace your launcher icon.</p>
-
-<p>For tips and recommendations on creating high-resolution launcher icons that
-can easily be scaled up to 512x512, see
-<a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#design-tips">
-Tips for Designers</a>.</p>
-
-<p>For information and specifications about high-resolution application
-icons in Android Market, see the following article:</p>
-
-<p style="margin-left:2em"><a
-href="http://market.android.com/support/bin/answer.py?answer=1078870">
- Graphic Assets for your Application (Android Market Help) »</a>
+</p>
+<h2 id="goals">Goals of the Launcher Icon</h2>
-<h2 id="icon5">Android 2.0 and Later</h2>
-
-<p>Starting with Android 2.0, launcher icons should be front-facing, instead of
-at a three-quarter perspective. The following guidelines describe how to design
-launcher icons for Android 2.0 (API Level 5) and later.</p>
-
-<h3 id="style5">Style</h3>
-
-<p>The launcher icons that you create should follow the general style principles
-below. The guidelines aren't meant to restrict what you can do with your icons,
-but rather they are meant to emphasize the common approaches that your icons can
-share with others on the device. Figure 1, at right, provides examples. </p>
-
-<div class="figure">
- <img src="{@docRoot}images/icon_design/IconGraphic_Icons_i.png"
- width="340">
+<div class="figure" style="width:400px" id="launcher_examples">
+ <img src="{@docRoot}images/icon_design/launcher_examples.png"
+ alt="Example launcher icons for system and third-party applications"
+ width="400" />
<p class="img-caption">
- <strong>Figure 1.</strong> Example launcher icons for Android 2.0 and
- greater.
+ <strong>Figure 1.</strong> Example launcher icons for system applications (left) and
+ third-party applications (right).
</p>
</div>
-<p>Clean and contemporary:</p>
-<ul>
- <li>Launcher icons should be modern and sometimes quirky; they should not
-appear aged or ragged. You should avoid overused symbolic metaphors whenever
-possible.</li>
-</ul>
+<p>Application launcher icons have three primary goals:</p>
-<p>Simple and iconic:</p>
-<ul>
- <li>Android Launcher icons are caricatural in nature; your icons should be
-highly simplified and exaggerated, so that they are appropriate for use at small
-sizes. Your icons should not be overly complicated. </li>
- <li>Try featuring a single part of an application as a symbolic
-representation of the whole (for example, the Music icon features a speaker).
-</li>
- <li>Consider using natural outlines and shapes, both geometric and organic,
-with a realistic (but never photorealistic) rendering. </li>
- <li>Your icons <em>should not</em> present a cropped view of a larger
-image.</li>
-</ul>
-
-<p>Tactile and textured:</p>
-<ul>
- <li>Icons should feature non-glossy, textured material. See
- <a href="#materialscolors5">Materials and colors</a>, below, for more
- information.</li>
-</ul>
-
-<p>Forward-facing and top-lit:</p>
-<ul>
- <li><em>New for Android 2.0 and later platforms</em>: Android Launcher
-icons should be forward-facing, with very little perspective, and they
-should be top-lit.</li>
-</ul>
-
-<p class="note"><strong>Note:</strong> Android applies separate text labels
-using the application name when displaying launcher icons, so you should avoid
-embedding text in your icon and instead focus on designing a distinct and
-memorable icon.</p>
-
-
-
-<h3 id="size5">Size and positioning</h3>
-
-<p>Launcher icons should use a variety of shapes and forms that are scaled and
-positioned inside the asset to create consistent visual weight with other
-icons.</p>
-
-<p>Figure 2 illustrates various ways of positioning the icon inside the
-asset. You should size the icons <em>smaller than the actual bounds of the
-asset</em> to create a consistent visual weight and to allow for shadows. If
-your icon is square or nearly square, it should be scaled even smaller.</p>
-
-<p>In order to indicate the recommended size for the icon, each example in
-Figure 2 includes three different guide rectangles:</p>
-
-<ul>
-<li>The red box is the bounding box for the full asset.</li>
-<li>The blue box is the recommended bounding box for the actual icon.
-The icon box is sized smaller than the full asset box so that there is space to
-include shadows and allow for special icon treatments.</li>
-<li>The orange box is the recommended bounding box for the actual icon when
-the content is square. The box for square icons is smaller than that for other
-icons to establish a consistent visual weight across the two types.</li>
-</ul>
-
-<table>
-<tr>
-
-<td style="border:0;">
-<ol class="nolist">
- <li>Launcher icon dimensions for high-density (<code>hdpi</code>) screens:</li>
- <ol class="nolist">
- <li>Full Asset: 72 x 72 px</li>
- <li>Icon: 60 x 60 px</li>
- <li>Square Icon: 56 x 56 px</li>
- </ol>
- </li>
+<ol>
+ <li>Promote the brand and tell the story of the app.</li>
+ <li>Help users discover the app in Android Market.</li>
+ <li>Function well in the Launcher.</li>
</ol>
-</td>
-<td style="border:0;">
- <img src="{@docRoot}images/icon_design/launcher_size_hdpi.png" width="450">
-</td>
-</tr>
-<tr>
-<td style="border:0;">
- <ol class="nolist">
- <li>Launcher icon dimensions for medium-density (<code>mdpi</code>) screens:</li>
- <ol class="nolist">
- <li>Full Asset: 48 x 48 px</li>
- <li>Icon: 40 x 40 px</li>
- <li>Square Icon: 38 x 38 px</li>
- </ol>
+
+<h3 id="promoting_brand_story">Promote the brand story</h3>
+
+<p>App launcher icons are an opportunity to showcase the brand and hint at the story of what your
+app is about. Thus, you should:</p>
+
+<ul>
+ <li>Create an icon that is unique and memorable.</li>
+ <li>Use a color scheme that suits your brand.</li>
+ <li>Don't try to communicate too much with the icon. A simple icon will have more impact and be
+ more memorable.</li>
+ <li>Avoid including the application name in the icon. The app name will always be displayed
+ adjacent to the icon.</li>
+</ul>
+
+
+<h3 id="help_users_discover">Help users discover the app in Android Market</h3>
+
+<p>App launcher icons are the first look that prospective users will get of your app in Android
+Market. A high quality app icon can influence users to find out more as they scroll through lists of
+applications.</p>
+
+<p>Quality matters here. A well-designed icon can be a strong signal that your app
+is of similarly high quality. Consider working with an icon designer to develop the app’s launcher
+icon.</p>
+
+<p class="note"><strong>Note:</strong> Android Market requires a high-resolution version of your
+icon; for more details on this, see <a href="#icons_in_market">Application Icons in Android
+Market</a> below.</p>
+
+
+<h3 id="function_well_in_launcher">Function well in the Launcher</h3>
+
+<p>The launcher is where users will interact with the icon most frequently. A successful app
+launcher icon will look great in all situations: on any background and next to any other icons and
+app widgets. To do this, icons should:</p>
+
+<ul>
+ <li>Communicate well at small sizes.</li>
+ <li>Work on a wide variety of backgrounds.</li>
+ <li>Reflect the implied lighting model of the launcher (top-lit).</li>
+ <li>If the icon is 3D, use a perspective that doesn't feel out of place with other icons;
+ forward-facing works best. <ul>
+ <li>3D icons work best with a shallow depth.</li></ul>
</li>
-</ol>
-</td>
-
-<td style="border:0;">
- <img src="{@docRoot}images/icon_design/launcher_size_mdpi.png" width="450">
-</td>
-</tr>
-<tr>
-<td style="border:0;">
- <ol class="nolist">
- <li>Launcher icon dimensions for low-density (<code>ldpi</code>) screens:</li>
- <ol class="nolist">
- <li>Full Asset: 36 x 36 px</li>
- <li>Icon: 30 x 30 px</li>
- <li>Square Icon: 28 x 28 px</li>
- </ol>
+ <li>Have a unique silhouette for faster recognition; not all Android app icons should be square. <ul>
+ <li>Icons should not present a cropped view of a larger image.</li></ul>
</li>
-</ol>
-</td>
-
-<td style="border:0;">
- <img src="{@docRoot}images/icon_design/launcher_size_ldpi.png" width="450">
-</td>
-</tr>
-
-<tr>
-<td style="border:0;"></td>
-<td style="border:0;">
- <p class="table-caption"><strong>Figure 2.</strong>
- Launcher icon sizing and positioning inside the bounds of the
- icon asset.</p>
-</td>
-</tr>
-
-</table>
+ <li>Have similar weight to other icons. Icons that are too spindly or that don't use enough of
+ the space may not successfully attract the user’s attention, or may not stand out well on all
+ backgrounds.</li>
+</ul>
+<h2 id="dos_donts">Do's and Don'ts</h2>
+<p>Below are some "do and don't" examples to consider when creating icons for your application.</p>
-<h3 id="materialscolors5">Materials and colors</h3>
-
-<p>Launcher icons should make use of tactile, top-lit, textured materials. Even
-if your icon is just a simple shape, you should try to render in a way that
-makes it appear to be sculpted from some real-world material.</p>
-
-<p>Android launcher icons usually consist of a smaller shape within a
-larger base shape and combine one neutral and one primary color. Icons may
-use a combination of neutral colors but should maintain a fairly high level of
-contrast. Icons should not use more than one primary color per icon, if
-possible.</p>
-
-<p>Launcher icons should use a limited color palette that includes a range
-of neutral and primary colors. The icons should not be over-saturated.</p>
-
-<p>The recommended color palette to use for Launcher icons is shown in Figure 3.
-You can use elements of the palette for both the base color and the highlight
-color. You can use the colors of the palette in conjunction with a
-white-to-black vertical linear gradient overlay. This creates the impression
-that the icon is lit from above and keeps the color less saturated.</p>
-
-<img src="{@docRoot}images/icon_design/IconGraphic_Colors.png" width="530">
-<p class="img-caption">
-<strong>Figure 3.</strong> Recommended color palette for icons.</p>
-
-<p>When you combine the materials in Figure 4 with a color highlight from the
-recommended palette above, you can create materials combinations such as those
-shown in Figure 5. To get you started, the
-<a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#templatespack">Icon Templates Pack</a>
-includes a Photoshop file (<code>ic_launcher_template/example_materials.psd</code>)
-that provides all of the default materials, colors, and gradients. </p>
-
-<table>
+<table style="width: 600px">
<tbody>
+
<tr>
- <td style="border:0;">
-<img src="{@docRoot}images/icon_design/IconGraphic_Materials.png" width="450">
-<p class="img-caption">
-<strong>Figure 4.</strong> Example materials that you can use to create
-your icons.</p>
- </td>
- <td style="border:0;border-left:1px solid #ccc;margin-left:1em;padding-left:1em">
-<img src="{@docRoot}images/icon_design/IconGraphic_AccentColor.png" width="450">
-<p class="img-caption">
-<strong>Figure 5.</strong> Examples of materials combined with base
-and highlight colors from the recommended palette.</p>
- </td>
+ <td style="border:0"><img src="{@docRoot}images/icon_design/launcher_dodont_settings.png"
+ alt="Side by side: overly complicated vs. simpler launcher icons"></td>
+ <td style="border:0; vertical-align:middle">Icons should not be overly complicated. Remember
+ that launcher icons will be used at often small sizes, so they should be distinguishable at
+ small sizes.</td>
</tr>
+
+ <tr>
+ <td style="border:0"><img src="{@docRoot}images/icon_design/launcher_dodont_clock.png"
+ alt="Side by side: cropped and glossy vs. matte and single-shape launcher icons"></td>
+ <td style="border:0; vertical-align:middle">Icons should not be cropped. Use unique shapes
+ where appropriate; remember that launcher icons should differentiate your application from
+ others. Additionally, do not use too glossy a finish unless the represented object has a
+ glossy material.</td>
+ </tr>
+
+ <tr>
+ <td style="border:0"><img src="{@docRoot}images/icon_design/launcher_dodont_custom_2.png"
+ alt="Side by side: overly thin vs. thicker, weightier icons"></td>
+ <td style="border:0; vertical-align:middle">Icons should not be thin. They should have a
+ similar weight to other icons. Overly thin icons will not stand out well on all
+ backgrounds.</td>
+ </tr>
+
+ <tr>
+ <td style="border:0"><img src="{@docRoot}images/icon_design/launcher_dodont_custom.png"
+ alt="Side by side: full-frame vs. subtly rounded and treated icons"></td>
+ <td style="border:0; vertical-align:middle">Icons should make use of the alpha channel, and
+ should not simply be full-frame images. Where appropriate, distinguish your icon with
+ subtle yet appealing visual treatment.</td>
+ </tr>
+
</tbody>
</table>
+<h2 id="size">Size and Format</h2>
-<h3 id="effects5">Effects</h3>
+<p>Launcher icons should be 32-bit PNGs with an alpha channel for transparency. The finished
+launcher icon dimensions corresponding to a given generalized screen density are shown in the
+table below.</p>
-<p>Launcher icons are flat and the perspective is straight-on, rather than at an
-angle. A drop shadow is used to create a sense of depth. Launcher icons can use
-varying textures and lighting effects, but must be lit directly from above
-(straight down).</p>
-
-<p>In order to maintain consistency, all launcher icons should use the same
-drop shadow effect, as shown in Figure 6.</p>
-
-<table class="image-caption">
-<tr>
-<td class="image-caption-i">
- <img src="{@docRoot}images/icon_design/launcher_style.png"/>
-</td>
-<td class="image-caption-c">
- <div class="caption grad-rule-top">
- <p><strong>Figure 6. </strong>Style, light and effects for launcher icons.</p>
- <div class="image-caption-nested">
- <p><em>Note: all pixel dimensions are for medium density and should be scaled appropriately for other densities.</em></p>
- <table>
- <tr><td><em>1.</em></td><td nowrap>Lighting:</td><td>Top-lit, using appropriate lighting details<br><br></td></tr>
- <tr><td><em>2.</em></td><td nowrap>Drop shadow:</td><td><code>#000000</code>, 75% opacity<br>angle 90°<br>distance 1px<br>size 3px<br><br></td></tr>
- <tr><td><em>3.</em></td><td nowrap>Textures:</td><td>Tactile, appear to use real-world materials (monochromatic noise in example image)<br><br></td></tr>
- </table>
- </div>
- </div>
-</td>
-</tr>
-</table>
-
-
-
-<h3 id="dodonts5">Do's and don'ts</h3>
-
-<p>Below are some "do and don't" examples to consider when creating icons for
-your application. </p>
-
+<p class="table-caption" id="screens_table"><strong>Table 1.</strong> Summary of
+finished launcher icon dimensions for each generalized screen density.</p>
<table>
-<tr>
-<td style="border:0;width:50%">
-
-<h4>Android Launcher icons are...</h4>
-
-<ul>
-<li>Modern, minimal, matte, tactile, and textured</li>
-<li>Forward-facing and top-lit, whole, limited in color
-palette</li>
-</ul>
-</td>
-<td style="border:0;width:50%">
-
-<h4>Android Launcher icons are not...</h4>
-
-<ul>
-<li>Antique, over-complicated, glossy, flat vector</li>
-<li>Rotated, Cropped, Over-Saturated</li>
-</ul>
-</td>
-</tr>
-<tr>
+ <tbody>
+ <tr>
+ <th></th>
+ <th>
+ <code>ldpi</code> (120 dpi)<br>
+ <small style="font-weight: normal">(Low density screen)</small>
+ </th>
+ <th>
+ <code>mdpi</code> (160 dpi)<br>
+ <small style="font-weight: normal">(Medium density screen)</small>
+ </th>
+ <th>
+ <code>hdpi</code> (240 dpi)<br>
+ <small style="font-weight: normal">(High density screen)</small>
+ </th>
+ <th>
+ <code>xhdpi</code> (320 dpi)<br>
+ <small style="font-weight: normal">(Extra-high density screen)</small>
+ </th>
+ </tr>
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Launcher Icon Size
+ </th>
+ <td>
+ 36 x 36 px
+ </td>
+ <td>
+ 48 x 48 px
+ </td>
+ <td>
+ 72 x 72 px
+ </td>
+ <td>
+ 96 x 96 px
+ </td>
+ </tr>
+ </tbody>
</table>
-<img src="{@docRoot}images/icon_design/IconGraphic_DosDonts.png"/>
-<p class="img-caption">
-<strong>Figure 7.</strong> Side-by-side examples of "do's and don'ts" for
-Android launcher icons. </p>
+<p>You can also include a few pixels of padding in launcher icons to maintain a
+consistent visual weight with adjacent icons. For example, a 96 x 96 pixel <code>xhdpi</code>
+launcher icon can contain a 88 x 88 pixel shape with 4 pixels on each side for padding.
+This padding can also be used to make room for a subtle drop shadow, which can help ensure
+that launcher icons are legible across on any background color.</p>
+<h3 id="icons_in_market">Application Icons in Android Market</h3>
+<p>If you are <a href="{@docRoot}guide/publishing/publishing.html">publishing your application on
+Android Market</a>, you will also need to provide a 512 x 512 pixel, high-resolution application icon
+in the <a href="http://market.android.com/publish">developer console</a> at upload time. This icon
+will be used in various locations in Android Market and does not replace your launcher icon.</p>
+<p>For tips and recommendations on creating high-resolution launcher icons that can easily be scaled
+up to 512x512, see <a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#design-tips">
+Tips for Designers</a>.</p>
-<h3 id="examples5">Example icons</h3>
+<p>For information and specifications about high-resolution application icons in Android Market, see
+the following article:</p>
-<p>Shown below are examples of high-density launcher icons used by
-Android applications. The icons are provided for your reference only —
-please do not reuse these icons in your applications.</code>.</p>
+<p style="margin-left:2em"><a href="http://market.android.com/support/bin/answer.py?answer=1078870">
+Graphic Assets for your Application (Android Market Help) »</a>
-<img src="{@docRoot}images/icon_design/IconGraphic_Icons.png" />
-
-
-
-<h2 id="icon1">Android 1.6 and earlier</h2>
-
-<p>The following guidelines describe how to design launcher icons for Android
-1.6 (API Level 4) and earlier. Launcher icons for Android 1.6 and below are
-simplified 3D icons with a fixed perspective. The required perspective is shown
-in Figure 8.</p>
-
-<h3 id="structure1">Structure</h3>
-
-<ul>
-<li>The base of a launcher icon can face either the top view or the front
-view.</li>
-
-<li>The majority of a launcher icon’s surface should be created using the
-launcher icon <a href="#palette1">color palette</a>. To add emphasis, use
-one or more bright accent colors to highlight specific characteristics.</li>
-
-<li>All launcher icons must be created with rounded corners to make them look
-friendly and simple—as shown in Figure 8.</li>
-
-<li>All dimensions specified are based on a 250x250 pixel artboard size
-in a vector graphics editor like Adobe Illustrator, where the icon fits within
-the artboard boundaries.</li>
-
-<li><strong>Final art must be scaled down and exported as a transparent PNG file
-using a raster image editor such as Adobe Photoshop. Do not include a background
-color.</strong></li>
-
-<li>Templates for creating icons in Adobe Photoshop are available in the <a
-href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#templatespack">Icon
-Templates Pack</a>.</li>
-
-</ul>
-
-<table class="image-caption">
-<tr>
-<td class="image-caption-i">
- <img src="{@docRoot}images/icon_design/launcher_structure.png" alt="A view of
-launcher icon corners and perspective angles" />
-</td>
-<td class="image-caption-c">
- <div class="caption grad-rule-top">
- <p><strong>Figure 8.</strong> Rounded corners and perspective angles for
- launcher icons (90° is vertical).</p>
- <div class="image-caption-nested">
- <table>
- <tr><td><em>1.</em></td><td>92°</td></tr>
- <tr><td><em>2.</em></td><td>92°</td></tr>
- <tr><td><em>3.</em></td><td>173°</td></tr>
- <tr><td><em>4.</em></td><td>171°</td></tr>
- <tr><td><em>5.</em></td><td>49°</td></tr>
- <tr><td><em>6.</em></td><td>171°</td></tr>
- <tr><td><em>7.</em></td><td>64°</td></tr>
- <tr><td><em>8.</em></td><td>97°</td></tr>
- <tr><td><em>9.</em></td><td>75°</td></tr>
- <tr><td><em>10.</em></td><td>93°</td></tr>
- <tr><td><em>11.</em></td><td>169°</td></tr>
- </table>
- </div>
- </div>
-</td>
-</tr>
-</table>
-
-<h3 id="style1">Light, effects, and shadows</h3>
-
-<p>Launcher icons are simplified 3D icons using light and shadows for
-definition. A light source is placed slightly to the left in front of the icon,
-and therefore the shadow expands to the right and back.</p>
-
-<table class="image-caption">
-<tr>
-<td class="image-caption-i">
- <img src="{@docRoot}images/icon_design/launcher_light.png" alt="A view of
-light, effects, and shadows for launcher icons."/>
-</td>
-<td class="image-caption-c">
- <div class="caption grad-rule-top">
- <p><strong>Figure 9. </strong>Light, effects, and shadows for launcher icons.</p>
- <div class="image-caption-nested">
- <table>
- <tr><td><em>1.</em></td><td>Edge highlight:</td><td>white</td></tr>
- <tr><td><em>2.</em></td><td>Icon shadow:</td><td>black | 20px blur<br>50% opacity | angle 67°</td></tr>
- <tr><td><em>3.</em></td><td>Front part:</td><td>Use light gradient from color palette</td></tr>
- <tr><td><em>4.</em></td><td>Detail shadow:</td><td>black | 10px blur<br>75% opacity</td></tr>
- <tr><td><em>5.</em></td><td> Side part:</td><td>Use medium gradient from color palette</td></tr>
- </table>
- </div>
- </div>
-</td>
-</tr>
-</table>
-
-<table>
-<tr>
-<td style="border:0">
-
-<h4 id="palette1">Launcher icon color palette</h4>
-
-<table>
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_white.png"/></td>
-<td class="image-caption-c">White<br>r 255 | g 255 | b 255<br>Used for highlights on edges.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_light.png"/></td>
-<td class="image-caption-c">Light gradient<br><em>1: </em>r 0 | g 0 | b 0<br><em>2: </em>r 217 | g 217 | b 217<br>Used on the front (lit) part of the icon.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_medium.png"/></td>
-<td class="image-caption-c">Medium gradient<br><em>1: </em>r 190 | g 190 | b 190<br><em>2: </em>r 115 | g 115 | b 115<br>Used on the side (shaded) part of the icon.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_dark.png"/></td>
-<td class="image-caption-c">Dark gradient<br><em>1: </em>r 100 | g 100 | b 100<br><em>2: </em>r 25 | g 25 | b 25<br>Used on details and parts in the shade of the icon.</td>
-</tr>
-
-<tr>
-<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_black.png"/></td>
-<td class="image-caption-c">Black<br>r 0 | g 0 | b 0<br>Used as base color in shadows.</td>
-</tr>
-
-</table>
-
-</td>
-
-<td style="border:0">
-
-<h4 id="steps1">Step by step</h4>
-
-<ol>
- <li>Create the basic shapes with a tool like Adobe Illustrator, using the
-angles described in <a href="#structure1">Launcher icon: structure</a>.
-The shapes and effects must fit within a 250x250 pixel artboard.</li>
- <li>Add depth to shapes by extruding them and create the rounded corners as
-described for the launcher icon structure.</li>
- <li>Add details and colors. Gradients should be treated as if there is a light
-source placed slightly to the left in front of the icon.</li>
- <li>Create the shadows with the correct angle and blur effect.</li>
- <li>Import the icon into a tool like Adobe Photoshop and scale to fit an image
-size of 48x48 px on a transparent background.</li>
- <li>Export the icon at 48x48 as a PNG file with transparency enabled.</li>
-</ol>
-
-</td>
-</tr>
-</table>
+<br><br>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_launcher_archive.jd b/docs/html/guide/practices/ui_guidelines/icon_design_launcher_archive.jd
new file mode 100644
index 0000000..ea036cd
--- /dev/null
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_launcher_archive.jd
@@ -0,0 +1,524 @@
+page.title=Launcher Icons (Archive)
+parent.title=Icon Design Guidelines
+parent.link=icon_design.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+
+<ol>
+<li><a href="#icon5">Android 2.0</a>
+ <ol>
+ <li><a href="#style5">Style</a></li>
+ <li><a href="#size5">Size</a></li>
+ <li><a href="#materialscolors5">Materials and colors</a></li>
+ <li><a href="#effects5">Effects</a></li>
+ <li><a href="#dodonts5">Do's and don'ts</a></li>
+ <li><a href="#examples5">Example icons</a></li>
+ </ol>
+</li>
+<li><a href="#icon1">Android 1.6 and Earlier</a></li>
+</ol>
+
+<h2>See also</h2>
+
+<ol>
+<li><a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a></li>
+</ol>
+
+</div>
+</div>
+
+<p class="warning">
+ <strong>Warning:</strong> This document describes obsolete guidelines for
+ creating launcher icons. Follow the <a href="icon_design_launcher.html">latest
+ launcher icon guidelines</a> instead.
+</p>
+
+<p>A Launcher icon is a graphic that represents your application on the device's
+Home screen and in the Launcher window.</p>
+
+<p>The user opens the Launcher by touching the icon at the bottom of the Home
+screen. The Launcher opens and exposes the icons for all of the installed
+applications. The user selects an application and opens it by touching the
+Launcher icon or by means of any hardware navigation controls available, such as
+a trackball or d-pad.</p>
+
+<p>As described in <a href="icon_design.html#icon-sets">Providing
+Density-Specific Icon Sets</a>, you should create separate icons for low-,
+medium-, and high-density screens. This ensures that your icons will display
+properly across the range of devices on which your application can be installed.
+See <a href="icon_design.html#design-tips">Tips for Designers</a> for
+suggestions on how to work with multiple sets of icons.</p>
+
+
+
+<h2 id="market">Application Icons in Android Market</h2>
+
+<p>If you are <a href="{@docRoot}guide/publishing/publishing.html">publishing
+your application on Android Market</a>, you will also need to provide a 512x512
+pixel, high-resolution application icon in the <a
+href="http://market.android.com/publish">developer console</a> at upload-time.
+This icon will be used in various locations in Android Market and does
+not replace your launcher icon.</p>
+
+<p>For tips and recommendations on creating high-resolution launcher icons that
+can easily be scaled up to 512x512, see
+<a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#design-tips">
+Tips for Designers</a>.</p>
+
+<p>For information and specifications about high-resolution application
+icons in Android Market, see the following article:</p>
+
+<p style="margin-left:2em"><a
+href="http://market.android.com/support/bin/answer.py?answer=1078870">
+ Graphic Assets for your Application (Android Market Help) »</a>
+
+
+
+
+<h2 id="icon5">Android 2.0 and Later</h2>
+
+<p>Starting with Android 2.0, launcher icons should be front-facing, instead of
+at a three-quarter perspective. The following guidelines describe how to design
+launcher icons for Android 2.0 (API Level 5) and later.</p>
+
+<h3 id="style5">Style</h3>
+
+<p>The launcher icons that you create should follow the general style principles
+below. The guidelines aren't meant to restrict what you can do with your icons,
+but rather they are meant to emphasize the common approaches that your icons can
+share with others on the device. Figure 1, at right, provides examples. </p>
+
+<div class="figure">
+ <img src="{@docRoot}images/icon_design/IconGraphic_Icons_i.png"
+ width="340">
+ <p class="img-caption">
+ <strong>Figure 1.</strong> Example launcher icons for Android 2.0 and
+ greater.
+ </p>
+</div>
+
+<p>Clean and contemporary:</p>
+
+<ul>
+ <li>Launcher icons should be modern and sometimes quirky; they should not
+appear aged or ragged. You should avoid overused symbolic metaphors whenever
+possible.</li>
+</ul>
+
+<p>Simple and iconic:</p>
+<ul>
+ <li>Android Launcher icons are caricatural in nature; your icons should be
+highly simplified and exaggerated, so that they are appropriate for use at small
+sizes. Your icons should not be overly complicated. </li>
+ <li>Try featuring a single part of an application as a symbolic
+representation of the whole (for example, the Music icon features a speaker).
+</li>
+ <li>Consider using natural outlines and shapes, both geometric and organic,
+with a realistic (but never photorealistic) rendering. </li>
+ <li>Your icons <em>should not</em> present a cropped view of a larger
+image.</li>
+</ul>
+
+<p>Tactile and textured:</p>
+<ul>
+ <li>Icons should feature non-glossy, textured material. See
+ <a href="#materialscolors5">Materials and colors</a>, below, for more
+ information.</li>
+</ul>
+
+<p>Forward-facing and top-lit:</p>
+<ul>
+ <li><em>New for Android 2.0 and later platforms</em>: Android Launcher
+icons should be forward-facing, with very little perspective, and they
+should be top-lit.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> Android applies separate text labels
+using the application name when displaying launcher icons, so you should avoid
+embedding text in your icon and instead focus on designing a distinct and
+memorable icon.</p>
+
+
+
+<h3 id="size5">Size and positioning</h3>
+
+<p>Launcher icons should use a variety of shapes and forms that are scaled and
+positioned inside the asset to create consistent visual weight with other
+icons.</p>
+
+<p>Figure 2 illustrates various ways of positioning the icon inside the
+asset. You should size the icons <em>smaller than the actual bounds of the
+asset</em> to create a consistent visual weight and to allow for shadows. If
+your icon is square or nearly square, it should be scaled even smaller.</p>
+
+<p>In order to indicate the recommended size for the icon, each example in
+Figure 2 includes three different guide rectangles:</p>
+
+<ul>
+<li>The red box is the bounding box for the full asset.</li>
+<li>The blue box is the recommended bounding box for the actual icon.
+The icon box is sized smaller than the full asset box so that there is space to
+include shadows and allow for special icon treatments.</li>
+<li>The orange box is the recommended bounding box for the actual icon when
+the content is square. The box for square icons is smaller than that for other
+icons to establish a consistent visual weight across the two types.</li>
+</ul>
+
+<table>
+<tr>
+
+<td style="border:0;">
+<ol class="nolist">
+ <li>Launcher icon dimensions for high-density (<code>hdpi</code>) screens:</li>
+ <ol class="nolist">
+ <li>Full Asset: 72 x 72 px</li>
+ <li>Icon: 60 x 60 px</li>
+ <li>Square Icon: 56 x 56 px</li>
+ </ol>
+ </li>
+</ol>
+</td>
+<td style="border:0;">
+ <img src="{@docRoot}images/icon_design/launcher_size_hdpi.png" width="450">
+</td>
+</tr>
+<tr>
+<td style="border:0;">
+ <ol class="nolist">
+ <li>Launcher icon dimensions for medium-density (<code>mdpi</code>) screens:</li>
+ <ol class="nolist">
+ <li>Full Asset: 48 x 48 px</li>
+ <li>Icon: 40 x 40 px</li>
+ <li>Square Icon: 38 x 38 px</li>
+ </ol>
+ </li>
+</ol>
+</td>
+
+<td style="border:0;">
+ <img src="{@docRoot}images/icon_design/launcher_size_mdpi.png" width="450">
+</td>
+</tr>
+<tr>
+<td style="border:0;">
+ <ol class="nolist">
+ <li>Launcher icon dimensions for low-density (<code>ldpi</code>) screens:</li>
+ <ol class="nolist">
+ <li>Full Asset: 36 x 36 px</li>
+ <li>Icon: 30 x 30 px</li>
+ <li>Square Icon: 28 x 28 px</li>
+ </ol>
+ </li>
+</ol>
+</td>
+
+<td style="border:0;">
+ <img src="{@docRoot}images/icon_design/launcher_size_ldpi.png" width="450">
+</td>
+</tr>
+
+<tr>
+<td style="border:0;"></td>
+<td style="border:0;">
+ <p class="table-caption"><strong>Figure 2.</strong>
+ Launcher icon sizing and positioning inside the bounds of the
+ icon asset.</p>
+</td>
+</tr>
+
+</table>
+
+
+
+
+<h3 id="materialscolors5">Materials and colors</h3>
+
+<p>Launcher icons should make use of tactile, top-lit, textured materials. Even
+if your icon is just a simple shape, you should try to render in a way that
+makes it appear to be sculpted from some real-world material.</p>
+
+<p>Android launcher icons usually consist of a smaller shape within a
+larger base shape and combine one neutral and one primary color. Icons may
+use a combination of neutral colors but should maintain a fairly high level of
+contrast. Icons should not use more than one primary color per icon, if
+possible.</p>
+
+<p>Launcher icons should use a limited color palette that includes a range
+of neutral and primary colors. The icons should not be over-saturated.</p>
+
+<p>The recommended color palette to use for Launcher icons is shown in Figure 3.
+You can use elements of the palette for both the base color and the highlight
+color. You can use the colors of the palette in conjunction with a
+white-to-black vertical linear gradient overlay. This creates the impression
+that the icon is lit from above and keeps the color less saturated.</p>
+
+<img src="{@docRoot}images/icon_design/IconGraphic_Colors.png" width="530">
+<p class="img-caption">
+<strong>Figure 3.</strong> Recommended color palette for icons.</p>
+
+<p>When you combine the materials in Figure 4 with a color highlight from the
+recommended palette above, you can create materials combinations such as those
+shown in Figure 5. To get you started, the
+<a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#templatespack">Icon Templates Pack</a>
+includes a Photoshop file (<code>ic_launcher_template/example_materials.psd</code>)
+that provides all of the default materials, colors, and gradients. </p>
+
+<table>
+ <tbody>
+ <tr>
+ <td style="border:0;">
+<img src="{@docRoot}images/icon_design/IconGraphic_Materials.png" width="450">
+<p class="img-caption">
+<strong>Figure 4.</strong> Example materials that you can use to create
+your icons.</p>
+ </td>
+ <td style="border:0;border-left:1px solid #ccc;margin-left:1em;padding-left:1em">
+<img src="{@docRoot}images/icon_design/IconGraphic_AccentColor.png" width="450">
+<p class="img-caption">
+<strong>Figure 5.</strong> Examples of materials combined with base
+and highlight colors from the recommended palette.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+
+
+<h3 id="effects5">Effects</h3>
+
+<p>Launcher icons are flat and the perspective is straight-on, rather than at an
+angle. A drop shadow is used to create a sense of depth. Launcher icons can use
+varying textures and lighting effects, but must be lit directly from above
+(straight down).</p>
+
+<p>In order to maintain consistency, all launcher icons should use the same
+drop shadow effect, as shown in Figure 6.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/launcher_style.png"/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 6. </strong>Style, light and effects for launcher icons.</p>
+ <div class="image-caption-nested">
+ <p><em>Note: all pixel dimensions are for medium density and should be scaled appropriately for other densities.</em></p>
+ <table>
+ <tr><td><em>1.</em></td><td nowrap>Lighting:</td><td>Top-lit, using appropriate lighting details<br><br></td></tr>
+ <tr><td><em>2.</em></td><td nowrap>Drop shadow:</td><td><code>#000000</code>, 75% opacity<br>angle 90°<br>distance 1px<br>size 3px<br><br></td></tr>
+ <tr><td><em>3.</em></td><td nowrap>Textures:</td><td>Tactile, appear to use real-world materials (monochromatic noise in example image)<br><br></td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+
+
+<h3 id="dodonts5">Do's and don'ts</h3>
+
+<p>Below are some "do and don't" examples to consider when creating icons for
+your application. </p>
+
+
+<table>
+<tr>
+<td style="border:0;width:50%">
+
+<h4>Android Launcher icons are...</h4>
+
+<ul>
+<li>Modern, minimal, matte, tactile, and textured</li>
+<li>Forward-facing and top-lit, whole, limited in color
+palette</li>
+</ul>
+</td>
+<td style="border:0;width:50%">
+
+<h4>Android Launcher icons are not...</h4>
+
+<ul>
+<li>Antique, over-complicated, glossy, flat vector</li>
+<li>Rotated, Cropped, Over-Saturated</li>
+</ul>
+</td>
+</tr>
+<tr>
+</table>
+
+<img src="{@docRoot}images/icon_design/IconGraphic_DosDonts.png"/>
+<p class="img-caption">
+<strong>Figure 7.</strong> Side-by-side examples of "do's and don'ts" for
+Android launcher icons. </p>
+
+
+
+
+
+<h3 id="examples5">Example icons</h3>
+
+<p>Shown below are examples of high-density launcher icons used by
+Android applications. The icons are provided for your reference only —
+please do not reuse these icons in your applications.</code>.</p>
+
+<img src="{@docRoot}images/icon_design/IconGraphic_Icons.png" />
+
+
+
+<h2 id="icon1">Android 1.6 and earlier</h2>
+
+<p>The following guidelines describe how to design launcher icons for Android
+1.6 (API Level 4) and earlier. Launcher icons for Android 1.6 and below are
+simplified 3D icons with a fixed perspective. The required perspective is shown
+in Figure 8.</p>
+
+<h3 id="structure1">Structure</h3>
+
+<ul>
+<li>The base of a launcher icon can face either the top view or the front
+view.</li>
+
+<li>The majority of a launcher icon’s surface should be created using the
+launcher icon <a href="#palette1">color palette</a>. To add emphasis, use
+one or more bright accent colors to highlight specific characteristics.</li>
+
+<li>All launcher icons must be created with rounded corners to make them look
+friendly and simple—as shown in Figure 8.</li>
+
+<li>All dimensions specified are based on a 250x250 pixel artboard size
+in a vector graphics editor like Adobe Illustrator, where the icon fits within
+the artboard boundaries.</li>
+
+<li><strong>Final art must be scaled down and exported as a transparent PNG file
+using a raster image editor such as Adobe Photoshop. Do not include a background
+color.</strong></li>
+
+<li>Templates for creating icons in Adobe Photoshop are available in the <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#templatespack">Icon
+Templates Pack</a>.</li>
+
+</ul>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/launcher_structure.png" alt="A view of
+launcher icon corners and perspective angles" />
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 8.</strong> Rounded corners and perspective angles for
+ launcher icons (90° is vertical).</p>
+ <div class="image-caption-nested">
+ <table>
+ <tr><td><em>1.</em></td><td>92°</td></tr>
+ <tr><td><em>2.</em></td><td>92°</td></tr>
+ <tr><td><em>3.</em></td><td>173°</td></tr>
+ <tr><td><em>4.</em></td><td>171°</td></tr>
+ <tr><td><em>5.</em></td><td>49°</td></tr>
+ <tr><td><em>6.</em></td><td>171°</td></tr>
+ <tr><td><em>7.</em></td><td>64°</td></tr>
+ <tr><td><em>8.</em></td><td>97°</td></tr>
+ <tr><td><em>9.</em></td><td>75°</td></tr>
+ <tr><td><em>10.</em></td><td>93°</td></tr>
+ <tr><td><em>11.</em></td><td>169°</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<h3 id="style1">Light, effects, and shadows</h3>
+
+<p>Launcher icons are simplified 3D icons using light and shadows for
+definition. A light source is placed slightly to the left in front of the icon,
+and therefore the shadow expands to the right and back.</p>
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/launcher_light.png" alt="A view of
+light, effects, and shadows for launcher icons."/>
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 9. </strong>Light, effects, and shadows for launcher icons.</p>
+ <div class="image-caption-nested">
+ <table>
+ <tr><td><em>1.</em></td><td>Edge highlight:</td><td>white</td></tr>
+ <tr><td><em>2.</em></td><td>Icon shadow:</td><td>black | 20px blur<br>50% opacity | angle 67°</td></tr>
+ <tr><td><em>3.</em></td><td>Front part:</td><td>Use light gradient from color palette</td></tr>
+ <tr><td><em>4.</em></td><td>Detail shadow:</td><td>black | 10px blur<br>75% opacity</td></tr>
+ <tr><td><em>5.</em></td><td> Side part:</td><td>Use medium gradient from color palette</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+<table>
+<tr>
+<td style="border:0">
+
+<h4 id="palette1">Launcher icon color palette</h4>
+
+<table>
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_white.png"/></td>
+<td class="image-caption-c">White<br>r 255 | g 255 | b 255<br>Used for highlights on edges.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_light.png"/></td>
+<td class="image-caption-c">Light gradient<br><em>1: </em>r 0 | g 0 | b 0<br><em>2: </em>r 217 | g 217 | b 217<br>Used on the front (lit) part of the icon.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_medium.png"/></td>
+<td class="image-caption-c">Medium gradient<br><em>1: </em>r 190 | g 190 | b 190<br><em>2: </em>r 115 | g 115 | b 115<br>Used on the side (shaded) part of the icon.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_gradient_dark.png"/></td>
+<td class="image-caption-c">Dark gradient<br><em>1: </em>r 100 | g 100 | b 100<br><em>2: </em>r 25 | g 25 | b 25<br>Used on details and parts in the shade of the icon.</td>
+</tr>
+
+<tr>
+<td class="image-caption-i"><img src="{@docRoot}images/icon_design/launcher_palette_black.png"/></td>
+<td class="image-caption-c">Black<br>r 0 | g 0 | b 0<br>Used as base color in shadows.</td>
+</tr>
+
+</table>
+
+</td>
+
+<td style="border:0">
+
+<h4 id="steps1">Step by step</h4>
+
+<ol>
+ <li>Create the basic shapes with a tool like Adobe Illustrator, using the
+angles described in <a href="#structure1">Launcher icon: structure</a>.
+The shapes and effects must fit within a 250x250 pixel artboard.</li>
+ <li>Add depth to shapes by extruding them and create the rounded corners as
+described for the launcher icon structure.</li>
+ <li>Add details and colors. Gradients should be treated as if there is a light
+source placed slightly to the left in front of the icon.</li>
+ <li>Create the shadows with the correct angle and blur effect.</li>
+ <li>Import the icon into a tool like Adobe Photoshop and scale to fit an image
+size of 48x48 px on a transparent background.</li>
+ <li>Export the icon at 48x48 as a PNG file with transparency enabled.</li>
+</ol>
+
+</td>
+</tr>
+</table>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd b/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd
index 2029def..974e48f 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_menu.jd
@@ -9,7 +9,8 @@
<h2>In this document</h2>
<ol>
-<li><a href="#icon9">Android 2.3 and Later</a>
+<li><a href="#icon11">Android 3.0 and Later</a>
+<li><a href="#icon9">Android 2.3</a>
<ol>
<li><a href="#size9">Size</a></li>
<li><a href="#style9">Style, colors, and effects</a></li>
@@ -37,11 +38,13 @@
in greyscale. Elements in a menu icon must not be visualized in 3D or
perspective.</p>
-<p>As described in <a href="icon_design.html#icon-sets">Providing
-Density-Specific Icon Sets</a>, you should create separate icon sets for low-,
-medium-, and high-density screens. This ensures that your icons will display
-properly across the range of devices on which your application can be installed.
-See <a href="icon_design.html#design-tips">Tips for Designers</a>
+<p>As described in <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#icon-sets">Providing Density-Specific
+Icon Sets</a> and <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a>, you should create separate icons for all generalized screen densities, including low-,
+medium-, high-, and extra-high-density screens. This ensures that your icons will display properly
+across the range of devices on which your application can be installed. See <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#design-tips">Tips for Designers</a>
for suggestions on how to work with multiple sets of icons.</p>
<p><strong>Final art must be exported as a transparent PNG file. Do not include
@@ -52,6 +55,16 @@
Templates Pack</a>.</p>
+<h2 id="icon11">Android 3.0 and Later</h2>
+
+<p>As of Android 3.0, the options menu has been superseded by the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>. Please refer to the <a
+href="icon_design_action_bar.html">Action Bar Icon Design Guidelines</a> for recommendations on
+creating icons for action items.</p>
+
+
+<h2 id="icon9">Android 2.3</h2>
+
<p class="caution"><strong>Caution:</strong> The style and content sizing of
menu icons have changed in Android 2.3 compared to
<a href="#icon1">previous versions</a>:
@@ -67,12 +80,8 @@
</p>
-
-
-<h2 id="icon9">Android 2.3 and Later</h2>
-
<p>The following guidelines describe how to design menu icons for Android
-2.3 (API Level 9) and later.</p>
+2.3 (API Levels 9 and 10).</p>
<h3 id="size9">Size and positioning</h3>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd b/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd
index 1fc3528..b8e07b5 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_status_bar.jd
@@ -9,11 +9,20 @@
<h2>In this document</h2>
<ol>
-<li><a href="#icon9">Android 2.3 and Later</a>
+<li><a href="#icon11">Android 3.0 and Later</a>
+ <ol>
+ <li><a href="#overview11">Overview of changes</a></li>
+ <li><a href="#size11">Size and format</a></li>
+ <li><a href="#style11">Style, colors, and effects</a></li>
+ <li><a href="#dimming11">Automatic dimming</a></li>
+ <li><a href="#examples11">Example icons</a></li>
+ </ol>
+</li>
+<li><a href="#icon9">Android 2.3</a>
<ol>
<li><a href="#size9">Size</a></li>
<li><a href="#style9">Style, color, and effects</a></li>
- <li><a href="#dodonts9">Do's and don'ts</a></li>
+ <li><a href="#dosdonts9">Do's and don'ts</a></li>
<li><a href="#examples9">Example icons</a></li>
</ol>
</li>
@@ -35,54 +44,217 @@
<p>Status bar icons are used to represent notifications from your application in
the status bar.</p>
-<p>As described in <a href="icon_design.html#icon-sets">Providing
-Density-Specific Icon Sets</a>, you should create separate icon sets for low-,
-medium-, and high-density screens. This ensures that your icons will display
-properly across the range of devices on which your application can be installed.
-See <a href="icon_design.html#design-tips">Tips for Designers</a> for
-suggestions on how to work with multiple sets of icons.</p>
-
-<p><strong>Final art must be exported as a transparent PNG file. Do not include
-a background color</strong>.</p>
+<p>As described in <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#icon-sets">Providing Density-Specific
+Icon Sets</a> and <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+Screens</a>, you should create separate icons for all generalized screen densities, including low-,
+medium-, high-, and extra-high-density screens. This ensures that your icons will display properly
+across the range of devices on which your application can be installed. See <a
+href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#design-tips">Tips for Designers</a>
+for suggestions on how to work with multiple sets of icons.</p>
<p>Templates for creating icons in Adobe Photoshop are available in the <a
href="{@docRoot}guide/practices/ui_guidelines/icon_design.html#templatespack">Icon
Templates Pack</a>.</p>
-<p class="warning"><strong>Warning:</strong>
+<div class="warning">
-The style and dimensions of status bar icons have changed drastically in
-Android 2.3 compared to <a href="#icon1">previous versions</a>. <strong>To
-provide support for all Android versions</strong>, developers should:
-<br>
-1. Place status bar icons for Android 2.3 and higher in the
-<code>drawable-hdpi-v9</code>, <code>drawable-mdpi-v9</code>, and <code>drawable-ldpi-v9</code> directories.
-<br>
-2. Place status bar icons for previous versions in
-<code>drawable-hdpi</code>, <code>drawable-mdpi</code>, and <code>drawable-ldpi</code> directories.
+<p><strong>Warning:</strong>The style and dimensions of status bar icons have changed dramatically
+in Android 3.0 and 2.3 compared to <a href="#icon1">previous versions</a>. <strong>To
+provide support for all Android versions</strong>, developers should:</p>
+<ol>
+<li>Place status bar icons for Android 3.0 and later in the
+ <code>drawable-xhdpi-v11</code>, <code>drawable-hdpi-v11</code>,<code>drawable-mdpi-v11</code>,
+ and <code>drawable-ldpi-v11</code> directories.</li>
+<li>Place status bar icons for Android 2.3 in the
+ <code>drawable-xhdpi-v9</code>, <code>drawable-hdpi-v9</code>, <code>drawable-mdpi-v9</code>,
+ and <code>drawable-ldpi-v9</code> directories.</li>
+<li>Place status bar icons for previous versions in
+ <code>drawable-xhdpi</code>, <code>drawable-hdpi</code>, <code>drawable-mdpi</code>,
+ and <code>drawable-ldpi</code> directories.</li>
+</ol>
+
+</div>
+
+
+
+
+<h2 id="icon11">Android 3.0 and Later</h2>
+
+<p>The following guidelines describe how to design status bar icons for Android
+3.0 (API Level 11) and later.</p>
+
+
+<h3 id="overview11">Overview of changes</h3>
+
+<p>The design for status bar (notification) icons has been revised in Android 3.0. Status bar icons
+ used in Android 3.0 and later are easier to create, and they allow for more flexible presentation
+ in a variety of situations:</p>
+
+<ul>
+ <li>Status bar icons are composed simply of <strong>white pixels on a transparent
+ backdrop</strong>, with alpha blending used for smooth edges and internal texture where
+ appropriate.</li>
+ <li>Icons are square icon contents should <strong>fill the available space</strong>, although a
+ small amount of internal padding can help maintain balance across status bar icons. See
+ <a href="#size11">Size and format</a> below for details.</li>
+</ul>
+
+<p>These larger and brighter icons, while highly legible, are too intense for use on dark phone
+status bars. These icons would be too distracting if used directly in the status bar. Therefore:
+</p>
+
+<ul>
+ <li><strong>The system automatically resizes and dims</strong> these icons in such situations and
+ developers do not need to supply a separate icon for this purpose. See
+ <a href="#dimming11">Automatic dimming</a> below for more on this behavior.</li>
+</ul>
+
+
+<h3 id="size11">Size and format</h2>
+
+<p>Status bar icons should be 32-bit PNGs with an alpha channel for transparency. The finished
+status bar icon dimensions corresponding to a given generalized screen density are shown in the
+table below.</p>
+
+<p class="note"><strong>Note:</strong> The system will shrink and dim status bar icons to minimize
+distractions, allowing users to focus on the foreground activity.</p>
+
+
+<p class="table-caption" id="screens_table"><strong>Table 1.</strong> Summary of
+finished icon dimensions for each generalized screen density.</p>
+
+<table>
+ <tbody>
+ <tr>
+ <th></th>
+ <th>
+ <code>ldpi</code> (120 dpi)<br>
+ <small style="font-weight: normal">(Low density screen)</small>
+ </th>
+ <th>
+ <code>mdpi</code> (160 dpi)<br>
+ <small style="font-weight: normal">(Medium density screen)</small>
+ </th>
+ <th>
+ <code>hdpi</code> (240 dpi)<br>
+ <small style="font-weight: normal">(High density screen)</small>
+ </th>
+ <th>
+ <code>xhdpi</code> (320 dpi)<br>
+ <small style="font-weight: normal">(Extra-high density screen)</small>
+ </th>
+ </tr>
+ <tr>
+ <th style="background-color:#f3f3f3;font-weight:normal">
+ Status Bar Icon Size<br><small>(Android 3.0 and Later)</small>
+ </th>
+ <td>
+ 18 x 18 px
+ </td>
+ <td>
+ 24 x 24 px
+ </td>
+ <td>
+ 36 x 36 px
+ </td>
+ <td>
+ 48 x 48 px
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>You can also include a few pixels of padding in status bar icons to maintain a
+consistent visual weight with adjacent icons. For example, a 48 x 48 pixel <code>xhdpi</code>
+status bar icon can contain a 44 x 44 pixel shape with 2 pixels on each side for padding.</p>
+
+
+<h3 id="style11">Style, colors, and effects</h3>
+
+<p>Status bar icons are flat, pictured face on, and must be white on a transparent background.</p>
+
+<p>In order to maintain consistency across all status bar notifications, status bar icons should
+use the styling shown in Figure 1.</p>
+
+
+
+<table class="image-caption">
+<tr>
+<td class="image-caption-i">
+ <img src="{@docRoot}images/icon_design/status_bar_honeycomb_style.png"
+ alt="A view of effects for status bar icons.">
+</td>
+<td class="image-caption-c">
+ <div class="caption grad-rule-top">
+ <p><strong>Figure 1. </strong>Style for status bar icons.</p>
+ <div class="image-caption-nested">
+ <table>
+ <tr><td><em>1.</em></td><td nowrap>Fill color:</td><td><code>#ffffff</code><br><br></td></tr>
+ <tr><td><em>2.</em></td><td nowrap>Inner content:</td><td>Inner content should subtract from
+ the outer shape and consist purely of transparent pixels.</td></tr>
+ </table>
+ </div>
+ </div>
+</td>
+</tr>
+</table>
+
+
+<h3 id="dimming11">Automatic dimming</h3>
+
+<p>The system may dim and shrink status bar icons to allow users to focus on the foreground
+activity. For example, in Android 4.0, the platform-standard status bar for handset-size devices
+reduces icons to 18 x 18 dip and 40% opacity in the status bar, while drawing them full-size and at
+full intensity in the expanded notification panel. An example of what this looks like is shown below
+in Figure 2.</p>
+
+
+<img src="{@docRoot}images/icon_design/status_bar_honeycomb_dimming.png"
+ alt="Automatic shrinking and dimming behavior in Android 3.0 and later">
+<p class="img-caption">
+ <strong>Figure 2.</strong> Automatic shrinking and dimming behavior in Android 3.0 and later.
</p>
+<h3 id="examples11">Example icons</h3>
-<h2 id="icon9">Android 2.3 and Later</h2>
+<p>Shown below are example extra-high-density status bar icons that are used throughout Android
+system applications.</p>
+
+<p class="warning"><strong>Warning:</strong> Because resources can change between platform versions,
+you should not reference built-in icons using the Android platform resource IDs (i.e. status bar
+icons under <code>android.R.drawable</code>). If you want to use any icons or other internal
+drawable resources, you should store a local copy of those icons or drawables in your application
+resources, then reference the local copy from your application code. In that way, you can maintain
+control over the appearance of your icons, even if the system's copy changes. Note that the grid
+below is not intended to be complete.</p>
+
+<img src="{@docRoot}images/icon_design/status_bar_honeycomb_examples.png" />
+
+
+
+
+
+<h2 id="icon9">Android 2.3</h2>
<p>The following guidelines describe how to design status bar icons for Android
-2.3 (API Level 9) and later.</p>
+2.3 (API Levels 9 and 10).</p>
<h3 id="size9">Size and positioning</h3>
<p>Status bar icons should use simple shapes and forms and those must be
scaled and positioned inside the final asset.</p>
-<p>Figure 1 illustrates various ways of positioning the icon inside the
+<p>Figure 3 illustrates various ways of positioning the icon inside the
asset. You should size the icons <em>smaller than the actual bounds of the
asset</em>. <strong>Status bar icons may vary in width, but only
minimally.</strong></p>
<p>In order to indicate the recommended size for the icon, each example in
-Figure 1 includes two different guide rectangles:</p>
+Figure 3 includes two different guide rectangles:</p>
<ul>
<li>The red box is the bounding box for the full asset.</li>
@@ -144,7 +316,7 @@
<tr>
<td style="border:0;"></td>
<td style="border:0;">
- <p class="table-caption"><strong>Figure 1.</strong>
+ <p class="table-caption"><strong>Figure 3.</strong>
Status bar icon sizing and positioning inside the bounds of the
icon asset.</p>
</td>
@@ -167,7 +339,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 2. </strong>Style and effects for status icons.</p>
+ <p><strong>Figure 4. </strong>Style and effects for status icons.</p>
<div class="image-caption-nested">
<p><em>Note: all pixel dimensions are for medium density and should be scaled appropriately for other densities.</em></p>
<table>
@@ -223,7 +395,7 @@
<ul>
<li>Rounded corners must always be applied to the base shape and to the details
-of a status bar icon shown Figure 3.</li>
+of a status bar icon shown Figure 5.</li>
<li>All dimensions specified are based on a 25x25 pixel artboard size with a 2
pixel safeframe.</li>
@@ -245,7 +417,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 3. </strong>Safeframe and corner-rounding for status bar
+ <p><strong>Figure 5. </strong>Safeframe and corner-rounding for status bar
icons. Icon size is 25x25.</p>
</div>
</td>
@@ -265,7 +437,7 @@
</td>
<td class="image-caption-c">
<div class="caption grad-rule-top">
- <p><strong>Figure 4. </strong>Light, effects, and shadows for status bar icons.</p>
+ <p><strong>Figure 6. </strong>Light, effects, and shadows for status bar icons.</p>
<div class="image-caption-nested">
<table>
<tr><td><em>1.</em></td><td>Front part:</td><td>Use fill gradient from primary color palette</td></tr>
@@ -320,8 +492,8 @@
<li>In a tool like Adobe Photoshop, create the base shape within a 25x25 px
image on a transparent background. Mind the safeframe, and keep the upper and
lower 2 pixels free.</li>
-<li>Add rounded corners as specified in Figure 3.</li>
-<li>Add light, effects, and shadows as specified in Figure 4.</li>
+<li>Add rounded corners as specified in Figure 5.</li>
+<li>Add light, effects, and shadows as specified in Figure 6.</li>
<li>Export the icon at 25x25 as a PNG file with transparency enabled.</li>
</ol>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd b/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd
index 1f96c3e..271bd85 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design_tab.jd
@@ -10,7 +10,7 @@
<ol>
<li><a href="#tabstates">Providing Icons for Two Tab States</a>
-<li><a href="#icon5">Android 2.0 and Later</a>
+<li><a href="#icon5">Android 2.0 through Android 2.3</a>
<ol>
<li><a href="#size5">Size</a></li>
<li><a href="#style5">Style, colors, and effects</a></li>
@@ -125,10 +125,10 @@
-<h2 id="icon5">Android 2.0 and Later</h2>
+<h2 id="icon5">Android 2.0 through Android 2.3</h2>
<p>The following guidelines describe how to design tab icons for Android
-2.0 (API Level 5) and later.</p>
+2.0 through Android 2.3 (API Levels 5 through 10).</p>
<h3 id="size5">Size and positioning</h3>
diff --git a/docs/html/guide/practices/ui_guidelines/index.jd b/docs/html/guide/practices/ui_guidelines/index.jd
index cb34d2e..0e42788 100644
--- a/docs/html/guide/practices/ui_guidelines/index.jd
+++ b/docs/html/guide/practices/ui_guidelines/index.jd
@@ -12,8 +12,8 @@
<dl>
<dt><a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Icon
Design Guidelines</a> and <a
-href="{@docRoot}shareables/icon_templates-v2.3.zip">Android Icon Templates Pack
-» </a></dt>
+href="{@docRoot}shareables/icon_templates-v4.0.zip">Android Icon Templates Pack
+» </a> <span class="new">updated</span></dt>
<dd>Your applications need a wide variety of icons, from a launcher icon to
icons in menus, dialogs, tabs, the status bar, and lists. The Icon Guidelines
describe each kind of icon in detail, with specifications for the size, color,
@@ -22,7 +22,7 @@
filters that make it much simpler to create conforming icons.</dd>
</dl>
<dl>
- <dt><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">Widget Design Guidelines</a> </dt>
+ <dt><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">Widget Design Guidelines</a> <span class="new">updated</span></dt>
<dd>A widget displays an application's most important or timely information
at a glance, on a user's Home screen. These design guidelines describe how to
design widgets that fit with others on the Home screen. They include links to
diff --git a/docs/html/images/icon_design/action_bar_examples.png b/docs/html/images/icon_design/action_bar_examples.png
new file mode 100644
index 0000000..b6b2b0a
--- /dev/null
+++ b/docs/html/images/icon_design/action_bar_examples.png
Binary files differ
diff --git a/docs/html/images/icon_design/action_bar_holo_dark_style.png b/docs/html/images/icon_design/action_bar_holo_dark_style.png
new file mode 100644
index 0000000..2837859
--- /dev/null
+++ b/docs/html/images/icon_design/action_bar_holo_dark_style.png
Binary files differ
diff --git a/docs/html/images/icon_design/action_bar_holo_light_style.png b/docs/html/images/icon_design/action_bar_holo_light_style.png
new file mode 100644
index 0000000..84e3655
--- /dev/null
+++ b/docs/html/images/icon_design/action_bar_holo_light_style.png
Binary files differ
diff --git a/docs/html/images/icon_design/launcher_dodont_clock.png b/docs/html/images/icon_design/launcher_dodont_clock.png
new file mode 100644
index 0000000..16fe651
--- /dev/null
+++ b/docs/html/images/icon_design/launcher_dodont_clock.png
Binary files differ
diff --git a/docs/html/images/icon_design/launcher_dodont_custom.png b/docs/html/images/icon_design/launcher_dodont_custom.png
new file mode 100644
index 0000000..fee3bff
--- /dev/null
+++ b/docs/html/images/icon_design/launcher_dodont_custom.png
Binary files differ
diff --git a/docs/html/images/icon_design/launcher_dodont_custom_2.png b/docs/html/images/icon_design/launcher_dodont_custom_2.png
new file mode 100644
index 0000000..d9fa1c9
--- /dev/null
+++ b/docs/html/images/icon_design/launcher_dodont_custom_2.png
Binary files differ
diff --git a/docs/html/images/icon_design/launcher_dodont_settings.png b/docs/html/images/icon_design/launcher_dodont_settings.png
new file mode 100644
index 0000000..2e689af
--- /dev/null
+++ b/docs/html/images/icon_design/launcher_dodont_settings.png
Binary files differ
diff --git a/docs/html/images/icon_design/launcher_examples.png b/docs/html/images/icon_design/launcher_examples.png
new file mode 100644
index 0000000..896a285
--- /dev/null
+++ b/docs/html/images/icon_design/launcher_examples.png
Binary files differ
diff --git a/docs/html/images/icon_design/status_bar_honeycomb_dimming.png b/docs/html/images/icon_design/status_bar_honeycomb_dimming.png
new file mode 100644
index 0000000..b319f45
--- /dev/null
+++ b/docs/html/images/icon_design/status_bar_honeycomb_dimming.png
Binary files differ
diff --git a/docs/html/images/icon_design/status_bar_honeycomb_examples.png b/docs/html/images/icon_design/status_bar_honeycomb_examples.png
new file mode 100644
index 0000000..6335426
--- /dev/null
+++ b/docs/html/images/icon_design/status_bar_honeycomb_examples.png
Binary files differ
diff --git a/docs/html/images/icon_design/status_bar_honeycomb_style.png b/docs/html/images/icon_design/status_bar_honeycomb_style.png
new file mode 100644
index 0000000..5844d8b
--- /dev/null
+++ b/docs/html/images/icon_design/status_bar_honeycomb_style.png
Binary files differ
diff --git a/docs/html/shareables/icon_templates-v4.0.zip b/docs/html/shareables/icon_templates-v4.0.zip
new file mode 100644
index 0000000..49e629f
--- /dev/null
+++ b/docs/html/shareables/icon_templates-v4.0.zip
Binary files differ
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index e2950d5e..d3d65a3 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -865,13 +865,7 @@
}
static int getTargetSdkVersion(Context ctx) {
- try {
- PackageManager pm = ctx.getPackageManager();
- ApplicationInfo app = pm.getApplicationInfo(ctx.getPackageName(), 0);
- return app.targetSdkVersion;
- } catch (Exception e) {
- throw new RSDriverException("Error calculating target SDK version for RS.");
- }
+ return ctx.getApplicationInfo().targetSdkVersion;
}
/**
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index 6afb291..9273533 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -150,6 +150,13 @@
ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen);
/**
+ * Convert UTF-8 to UTF-16 including surrogate pairs.
+ * Returns a pointer to the end of the string (where a null terminator might go
+ * if you wanted to add one).
+ */
+char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* src, size_t srcLen, char16_t* dst);
+
+/**
* Convert UTF-8 to UTF-16 including surrogate pairs. The destination buffer
* must be large enough to hold the result as measured by utf8_to_utf16_length
* plus an added NULL terminator.
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index dd05e61..a077cbc5 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -185,7 +185,7 @@
return;
}
- SkFixed penX = SkIntToFixed(x);
+ float penX = x;
int penY = y;
int glyphsLeft = 1;
if (numGlyphs > 0) {
@@ -193,7 +193,7 @@
}
SkFixed prevRsbDelta = 0;
- penX += SK_Fixed1 / 2;
+ penX += 0.5f;
text += start;
@@ -206,25 +206,25 @@
}
CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
- penX += SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta);
+ penX += SkFixedToFloat(SkAutoKern_AdjustF(prevRsbDelta, cachedGlyph->mLsbDelta));
prevRsbDelta = cachedGlyph->mRsbDelta;
// If it's still not valid, we couldn't cache it, so we shouldn't draw garbage
if (cachedGlyph->mIsValid) {
switch(mode) {
case FRAMEBUFFER:
- drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY);
+ drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY);
break;
case BITMAP:
- drawCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bitmap, bitmapW, bitmapH);
+ drawCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bitmap, bitmapW, bitmapH);
break;
case MEASURE:
- measureCachedGlyph(cachedGlyph, SkFixedFloor(penX), penY, bounds);
+ measureCachedGlyph(cachedGlyph, (int) floorf(penX), penY, bounds);
break;
}
}
- penX += cachedGlyph->mAdvanceX;
+ penX += SkFixedToFloat(cachedGlyph->mAdvanceX);
// If we were given a specific number of glyphs, decrement
if (numGlyphs > 0) {
diff --git a/libs/utils/Unicode.cpp b/libs/utils/Unicode.cpp
index 78c61b4..41cbf03 100644
--- a/libs/utils/Unicode.cpp
+++ b/libs/utils/Unicode.cpp
@@ -542,11 +542,7 @@
return u16measuredLen;
}
-/**
- * Convert a UTF-8 string to UTF-16. The destination UTF-16 buffer must have
- * space for NULL at the end.
- */
-void utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str)
+char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* u8str, size_t u8len, char16_t* u16str)
{
const uint8_t* const u8end = u8str + u8len;
const uint8_t* u8cur = u8str;
@@ -569,7 +565,12 @@
u8cur += u8len;
}
- *u16cur = 0;
+ return u16cur;
+}
+
+void utf8_to_utf16(const uint8_t* u8str, size_t u8len, char16_t* u16str) {
+ char16_t* end = utf8_to_utf16_no_null_terminator(u8str, u8len, u16str);
+ *end = 0;
}
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 23f67d5..1f9ce68 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1480,7 +1480,7 @@
}
}
- return setError(EGL_BAD_DISPLAY, 0);;
+ return setErrorQuiet(EGL_BAD_DISPLAY, 0);
}
EGLuint64NV eglGetSystemTimeNV()
@@ -1500,5 +1500,5 @@
}
}
- return setError(EGL_BAD_DISPLAY, 0);;
+ return setErrorQuiet(EGL_BAD_DISPLAY, 0);
}
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index f3c8d2c..b341ddb 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -67,19 +67,23 @@
}
}
-void egl_tls_t::setErrorEtcImpl(const char* caller, int line, EGLint error) {
+void egl_tls_t::setErrorEtcImpl(
+ const char* caller, int line, EGLint error, bool quiet) {
validateTLSKey();
egl_tls_t* tls = getTLS();
if (tls->error != error) {
- LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
- tls->error = error;
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.callstack", value, "0");
- if (atoi(value)) {
- CallStack stack;
- stack.update();
- stack.dump();
+ if (!quiet) {
+ LOGE("%s:%d error %x (%s)",
+ caller, line, error, egl_strerror(error));
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.callstack", value, "0");
+ if (atoi(value)) {
+ CallStack stack;
+ stack.update();
+ stack.dump();
+ }
}
+ tls->error = error;
}
}
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index a7989ef..78b0b2f 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -41,7 +41,8 @@
egl_tls_t();
static void validateTLSKey();
- static void setErrorEtcImpl(const char* caller, int line, EGLint error);
+ static void setErrorEtcImpl(
+ const char* caller, int line, EGLint error, bool quiet);
public:
static egl_tls_t* getTLS();
@@ -55,13 +56,17 @@
template<typename T>
static T setErrorEtc(const char* caller,
- int line, EGLint error, T returnValue) {
- setErrorEtcImpl(caller, line, error);
+ int line, EGLint error, T returnValue, bool quiet = false) {
+ setErrorEtcImpl(caller, line, error, quiet);
return returnValue;
}
};
-#define setError(_e, _r) egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
+#define setError(_e, _r) \
+ egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
+
+#define setErrorQuiet(_e, _r) \
+ egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r, true)
// ----------------------------------------------------------------------------
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c91f513..bf2d5e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -60,8 +60,7 @@
private static final int MSG_SHOW_IME_BUTTON = 9 << MSG_SHIFT;
private static final int MSG_SET_HARD_KEYBOARD_STATUS = 10 << MSG_SHIFT;
- private static final int MSG_USER_ACTIVITY = 11 << MSG_SHIFT;
- private static final int MSG_TOGGLE_RECENT_APPS = 12 << MSG_SHIFT;
+ private static final int MSG_TOGGLE_RECENT_APPS = 11 << MSG_SHIFT;
private StatusBarIconList mList;
private Callbacks mCallbacks;
@@ -90,7 +89,6 @@
public void topAppWindowChanged(boolean visible);
public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
public void setHardKeyboardStatus(boolean available, boolean enabled);
- public void userActivity();
public void toggleRecentApps();
}
@@ -191,13 +189,6 @@
}
}
- public void userActivity() {
- synchronized (mList) {
- mHandler.removeMessages(MSG_USER_ACTIVITY);
- mHandler.obtainMessage(MSG_USER_ACTIVITY, 0, 0, null).sendToTarget();
- }
- }
-
public void toggleRecentApps() {
synchronized (mList) {
mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
@@ -271,9 +262,6 @@
case MSG_SET_HARD_KEYBOARD_STATUS:
mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0);
break;
- case MSG_USER_ACTIVITY:
- mCallbacks.userActivity();
- break;
case MSG_TOGGLE_RECENT_APPS:
mCallbacks.toggleRecentApps();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index d260e6d..e3a64a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -17,9 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.os.ServiceManager;
@@ -27,14 +25,12 @@
import android.util.Slog;
import android.view.animation.AccelerateInterpolator;
import android.view.Display;
-import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Surface;
import android.view.WindowManager;
import android.widget.LinearLayout;
-import android.content.res.Configuration;
import com.android.internal.statusbar.IStatusBarService;
@@ -54,7 +50,6 @@
final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
- AnimatorSet mLastAnimator = null;
int mBarSize;
boolean mVertical;
@@ -204,43 +199,6 @@
// bring up the lights no matter what
setLowProfile(false);
-
- if (!ANIMATE_HIDE_TRANSITION) {
- setVisibility(hide ? View.GONE : View.VISIBLE);
- return;
- }
-
- float oldAlpha = mCurrentView.getAlpha();
- if (DEBUG) {
- Slog.d(TAG, "animating alpha: " + oldAlpha + " -> "
- + (!hide ? 1f : 0f));
- }
-
- if (mLastAnimator != null && mLastAnimator.isRunning()) mLastAnimator.cancel();
-
- if (!hide) {
- setVisibility(View.VISIBLE);
- }
-
- // play us off, animatorset
- mLastAnimator = new AnimatorSet();
- mLastAnimator.playTogether(
- ObjectAnimator.ofFloat(mCurrentView, "alpha", hide ? 0f : 1f),
- ObjectAnimator.ofFloat(mCurrentView,
- mVertical ? "translationX" : "translationY",
- hide ? mBarSize : 0)
- );
- mLastAnimator.setDuration(!hide ? 250 : 1000);
- mLastAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator _a) {
- mLastAnimator = null;
- if (hide) {
- setVisibility(View.GONE);
- }
- }
- });
- mLastAnimator.start();
}
public void onFinishInflate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d6e4d1b..09ea6ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -31,12 +31,8 @@
import android.content.res.Resources;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.net.Uri;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Handler;
@@ -471,6 +467,7 @@
0
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.OPAQUE);
@@ -2028,19 +2025,6 @@
}
}
- // The user is not allowed to get stuck without navigation UI. Upon the slightest user
- // interaction we bring the navigation back.
- public void userActivity() {
- if (0 != (mSystemUiVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) {
- try {
- mBarService.setSystemUiVisibility(
- mSystemUiVisibility & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
- } catch (RemoteException ex) {
- // weep softly
- }
- }
- }
-
public void toggleRecentApps() {
int msg = (mRecentsPanel.getVisibility() == View.GONE)
? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 54b45a9..ba52fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1822,9 +1822,6 @@
visibilityChanged(false);
}
- public void userActivity() {
- }
-
public void toggleRecentApps() {
int msg = (mRecentsPanel.getVisibility() == View.GONE)
? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL;
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 4049c73..071044e 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -526,11 +526,23 @@
if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
&& transportInvisible) {
bindToFaceLock();
+ //Eliminate the black background so that the lockpattern will be visible
+ //If FaceUnlock is cancelled
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_FACELOCK_AREA_VIEW, 4000);
} else {
mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW);
}
}
+ /** Unbind from facelock if something covers this window (such as an alarm) */
+ @Override
+ public void onWindowFocusChanged (boolean hasWindowFocus) {
+ if(!hasWindowFocus) {
+ stopAndUnbindFromFaceLock();
+ mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW);
+ }
+ }
+
@Override
public void show() {
if (mMode == Mode.LockScreen) {
@@ -607,7 +619,10 @@
//We need to stop faceunlock when a phonecall comes in
@Override
public void onPhoneStateChanged(int phoneState) {
- if(phoneState == TelephonyManager.CALL_STATE_RINGING) stopAndUnbindFromFaceLock();
+ if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
+ stopAndUnbindFromFaceLock();
+ mHandler.sendEmptyMessage(MSG_HIDE_FACELOCK_AREA_VIEW);
+ }
}
@Override
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 9e1dec7..487063d 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -103,6 +103,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_DRAG;
+import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
@@ -127,6 +128,7 @@
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
import android.view.KeyCharacterMap.FallbackAction;
+import android.view.WindowManagerPolicy.WindowManagerFuncs;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -205,6 +207,7 @@
static final int BOOT_PROGRESS_LAYER = 22;
// the (mouse) pointer layer
static final int POINTER_LAYER = 23;
+ static final int HIDDEN_NAV_CONSUMER_LAYER = 24;
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -220,10 +223,16 @@
private static final int SW_LID = 0x00;
private static final int BTN_MOUSE = 0x110;
+ /**
+ * Lock protecting internal state. Must not call out into window
+ * manager with lock held. (This lock will be acquired in places
+ * where the window manager is calling in with its own lock held.)
+ */
final Object mLock = new Object();
-
+
Context mContext;
IWindowManager mWindowManager;
+ WindowManagerFuncs mWindowManagerFuncs;
LocalPowerManager mPowerManager;
IStatusBarService mStatusBarService;
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -344,7 +353,11 @@
int mDockLeft, mDockTop, mDockRight, mDockBottom;
// During layout, the layer at which the doc window is placed.
int mDockLayer;
-
+ int mLastSystemUiVisibility;
+ int mForceClearingStatusBarVisibility = 0;
+
+ FakeWindow mHideNavFakeWindow = null;
+
static final Rect mTmpParentFrame = new Rect();
static final Rect mTmpDisplayFrame = new Rect();
static final Rect mTmpContentFrame = new Rect();
@@ -647,9 +660,11 @@
/** {@inheritDoc} */
public void init(Context context, IWindowManager windowManager,
+ WindowManagerFuncs windowManagerFuncs,
LocalPowerManager powerManager) {
mContext = context;
mWindowManager = windowManager;
+ mWindowManagerFuncs = windowManagerFuncs;
mPowerManager = powerManager;
mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
mHandler = new Handler();
@@ -1068,6 +1083,8 @@
return NAVIGATION_BAR_LAYER;
case TYPE_BOOT_PROGRESS:
return BOOT_PROGRESS_LAYER;
+ case TYPE_HIDDEN_NAV_CONSUMER:
+ return HIDDEN_NAV_CONSUMER_LAYER;
}
Log.e(TAG, "Unknown window type: " + type);
return APPLICATION_LAYER;
@@ -1646,6 +1663,46 @@
}
}
+ final InputHandler mHideNavInputHandler = new BaseInputHandler() {
+ @Override
+ public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
+ boolean handled = false;
+ try {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ // When the user taps down, we re-show the nav bar.
+ boolean changed = false;
+ synchronized (mLock) {
+ // Any user activity always causes us to show the navigation controls,
+ // if they had been hidden.
+ int newVal = mForceClearingStatusBarVisibility
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ if (mForceClearingStatusBarVisibility != newVal) {
+ mForceClearingStatusBarVisibility = newVal;
+ changed = true;
+ }
+ }
+ if (changed) {
+ mWindowManagerFuncs.reevaluateStatusBarVisibility();
+ }
+ }
+ }
+ } finally {
+ finishedCallback.finished(handled);
+ }
+ }
+ };
+
+ @Override
+ public int adjustSystemUiVisibilityLw(int visibility) {
+ // Reset any bits in mForceClearingStatusBarVisibility that
+ // are now clear.
+ mForceClearingStatusBarVisibility &= visibility;
+ // Clear any bits in the new visibility that are currently being
+ // force cleared, before reporting it.
+ return visibility & ~mForceClearingStatusBarVisibility;
+ }
+
public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
final int fl = attrs.flags;
@@ -1684,8 +1741,9 @@
// decide where the status bar goes ahead of time
if (mStatusBar != null) {
- Rect navr = null;
if (mNavigationBar != null) {
+ final boolean navVisible = mNavigationBar.isVisibleLw() &&
+ (mLastSystemUiVisibility&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
// Force the navigation bar to its appropriate place and
// size. We need to do this directly, instead of relying on
// it to bubble up from the nav bar, because this needs to
@@ -1694,19 +1752,45 @@
// Portrait screen; nav bar goes on bottom.
mTmpNavigationFrame.set(0, displayHeight-mNavigationBarHeight,
displayWidth, displayHeight);
- if (mNavigationBar.isVisibleLw()) {
+ if (navVisible) {
mDockBottom = mTmpNavigationFrame.top;
mRestrictedScreenHeight = mDockBottom - mDockTop;
+ } else {
+ // We currently want to hide the navigation UI. Do this by just
+ // moving it off the screen, so it can still receive input events
+ // to know when to be re-shown.
+ mTmpNavigationFrame.offset(0, mNavigationBarHeight);
}
} else {
// Landscape screen; nav bar goes to the right.
mTmpNavigationFrame.set(displayWidth-mNavigationBarWidth, 0,
displayWidth, displayHeight);
- if (mNavigationBar.isVisibleLw()) {
+ if (navVisible) {
mDockRight = mTmpNavigationFrame.left;
mRestrictedScreenWidth = mDockRight - mDockLeft;
+ } else {
+ // We currently want to hide the navigation UI. Do this by just
+ // moving it off the screen, so it can still receive input events
+ // to know when to be re-shown.
+ mTmpNavigationFrame.offset(mNavigationBarWidth, 0);
}
}
+ // When the navigation bar isn't visible, we put up a fake
+ // input window to catch all touch events. This way we can
+ // detect when the user presses anywhere to bring back the nav
+ // bar and ensure the application doesn't see the event.
+ if (navVisible) {
+ if (mHideNavFakeWindow != null) {
+ mHideNavFakeWindow.dismiss();
+ mHideNavFakeWindow = null;
+ }
+ } else if (mHideNavFakeWindow == null) {
+ mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
+ mHandler.getLooper(), mHideNavInputHandler,
+ "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
+ 0, false, false, true);
+ }
+ // And compute the final frame.
mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
mTmpNavigationFrame, mTmpNavigationFrame);
if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
@@ -2214,7 +2298,11 @@
}
}
- updateSystemUiVisibility();
+ if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
+ // If the navigation bar has been hidden or shown, we need to do another
+ // layout pass to update that window.
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ }
// update since mAllowLockscreenWhenOn might have changed
updateLockScreenTimeout();
@@ -2255,9 +2343,14 @@
return true;
}
- public void focusChanged(WindowState lastFocus, WindowState newFocus) {
+ public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
mFocusedWindow = newFocus;
- updateSystemUiVisibility();
+ if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
+ // If the navigation bar has been hidden or shown, we need to do another
+ // layout pass to update that window.
+ return FINISH_LAYOUT_REDO_LAYOUT;
+ }
+ return 0;
}
/** {@inheritDoc} */
@@ -3200,6 +3293,17 @@
/** {@inheritDoc} */
public void userActivity() {
+ // ***************************************
+ // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+ // ***************************************
+ // THIS IS CALLED FROM DEEP IN THE POWER MANAGER
+ // WITH ITS LOCKS HELD.
+ //
+ // This code must be VERY careful about the locks
+ // it acquires.
+ // In fact, the current code acquires way too many,
+ // and probably has lurking deadlocks.
+
synchronized (mScreenLockTimeout) {
if (mLockScreenTimerActive) {
// reset the timer
@@ -3208,14 +3312,11 @@
}
}
- if (mStatusBarService != null) {
- try {
- mStatusBarService.userActivity();
- } catch (RemoteException ex) {}
- }
-
- synchronized (mLock) {
- updateScreenSaverTimeoutLocked();
+ // Turn this off for now, screen savers not currently enabled.
+ if (false) {
+ synchronized (mLock) {
+ updateScreenSaverTimeoutLocked();
+ }
}
}
@@ -3257,6 +3358,9 @@
private void updateScreenSaverTimeoutLocked() {
if (mScreenSaverActivator == null) return;
+ // GAH... acquiring a lock within a lock? Please let's fix this.
+ // (Also note this is called from userActivity, with the power manager
+ // lock held. Not good.)
synchronized (mScreenSaverActivator) {
mHandler.removeCallbacks(mScreenSaverActivator);
if (mScreenSaverEnabled && mScreenOnEarly && mScreenSaverTimeout > 0) {
@@ -3493,32 +3597,36 @@
return mScreenOnEarly;
}
- private void updateSystemUiVisibility() {
+ private int updateSystemUiVisibilityLw() {
// If there is no window focused, there will be nobody to handle the events
// anyway, so just hang on in whatever state we're in until things settle down.
- if (mFocusedWindow != null) {
- final int visibility = mFocusedWindow.getSystemUiVisibility();
- mHandler.post(new Runnable() {
- public void run() {
- if (mStatusBarService == null) {
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService("statusbar"));
- }
- if (mStatusBarService != null) {
- // need to assume status bar privileges to invoke lights on
- long origId = Binder.clearCallingIdentity();
- try {
- mStatusBarService.setSystemUiVisibility(visibility);
- } catch (RemoteException e) {
- // not much to be done
- mStatusBarService = null;
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
+ if (mFocusedWindow == null) {
+ return 0;
+ }
+ final int visibility = mFocusedWindow.getSystemUiVisibility()
+ & ~mForceClearingStatusBarVisibility;
+ int diff = visibility ^ mLastSystemUiVisibility;
+ if (diff == 0) {
+ return 0;
+ }
+ mLastSystemUiVisibility = visibility;
+ mHandler.post(new Runnable() {
+ public void run() {
+ if (mStatusBarService == null) {
+ mStatusBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService("statusbar"));
+ }
+ if (mStatusBarService != null) {
+ try {
+ mStatusBarService.setSystemUiVisibility(visibility);
+ } catch (RemoteException e) {
+ // not much to be done
+ mStatusBarService = null;
}
}
- });
- }
+ }
+ });
+ return diff;
}
public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -3528,6 +3636,12 @@
pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
+ if (mLastSystemUiVisibility != 0 || mForceClearingStatusBarVisibility != 0) {
+ pw.print(prefix); pw.print("mLastSystemUiVisibility=0x");
+ pw.println(Integer.toHexString(mLastSystemUiVisibility));
+ pw.print(" mForceClearingStatusBarVisibility=0x");
+ pw.println(Integer.toHexString(mForceClearingStatusBarVisibility));
+ }
pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
pw.print(" mDockMode="); pw.print(mDockMode);
pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index ce31474..498bdfc 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -73,6 +73,7 @@
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.telephony.Phone;
+import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.google.android.collect.Lists;
@@ -1649,11 +1650,11 @@
}
private void handleConnect(NetworkInfo info) {
- int type = info.getType();
+ final int type = info.getType();
// snapshot isFailover, because sendConnectedBroadcast() resets it
boolean isFailover = info.isFailover();
- NetworkStateTracker thisNet = mNetTrackers[type];
+ final NetworkStateTracker thisNet = mNetTrackers[type];
// if this is a default net and other default is running
// kill the one not preferred
@@ -1710,6 +1711,16 @@
updateNetworkSettings(thisNet);
handleConnectivityChange(type, false);
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
+
+ // notify battery stats service about this network
+ final String iface = thisNet.getLinkProperties().getInterfaceName();
+ if (iface != null) {
+ try {
+ BatteryStatsService.getService().noteNetworkInterfaceType(iface, type);
+ } catch (RemoteException e) {
+ // ignored; service lives in system_server
+ }
+ }
}
/**
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 3e1fb9f..6ddbf5a 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -574,7 +574,7 @@
}
}
if (defIm == null && mMethodList.size() > 0) {
- defIm = mMethodList.get(0);
+ defIm = getMostApplicableDefaultIMELocked();
Slog.i(TAG, "No default found, using " + defIm.getId());
}
if (defIm != null) {
@@ -1925,19 +1925,26 @@
return subtypes;
}
- private boolean chooseNewDefaultIMELocked() {
+ private InputMethodInfo getMostApplicableDefaultIMELocked() {
List<InputMethodInfo> enabled = mSettings.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) {
+ final InputMethodInfo imi = enabled.get(i);
+ if (isSystemIme(imi) && !imi.isAuxiliaryIme()) {
break;
}
}
- InputMethodInfo imi = enabled.get(i);
+ return enabled.get(i);
+ }
+ return null;
+ }
+
+ private boolean chooseNewDefaultIMELocked() {
+ final InputMethodInfo imi = getMostApplicableDefaultIMELocked();
+ if (imi != null) {
if (DEBUG) {
Slog.d(TAG, "New default IME was selected: " + imi.getId());
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index f1a404a..b05705e 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -18,14 +18,12 @@
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
-import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
import static android.provider.Settings.Secure.NETSTATS_ENABLED;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -46,8 +44,7 @@
import android.util.Slog;
import android.util.SparseBooleanArray;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
+import com.android.internal.net.NetworkStatsFactory;
import com.google.android.collect.Sets;
import java.io.BufferedReader;
@@ -55,21 +52,17 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
-import libcore.io.IoUtils;
-
/**
* @hide
*/
@@ -82,42 +75,12 @@
private static final int ADD = 1;
private static final int REMOVE = 2;
- /** Path to {@code /proc/uid_stat}. */
- @Deprecated
- private final File mStatsUid;
- /** Path to {@code /proc/net/dev}. */
- @Deprecated
- private final File mStatsIface;
- /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
- @Deprecated
- private final File mStatsXtIface;
- /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
- private final File mStatsXtIfaceAll;
- /** Path to {@code /proc/net/xt_qtaguid/stats}. */
- private final File mStatsXtUid;
-
/**
* Name representing {@link #setGlobalAlert(long)} limit when delivered to
* {@link INetworkManagementEventObserver#limitReached(String, String)}.
*/
public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
- /** {@link #mStatsXtUid} and {@link #mStatsXtIfaceAll} headers. */
- private static final String KEY_IDX = "idx";
- private static final String KEY_IFACE = "iface";
- private static final String KEY_ACTIVE = "active";
- private static final String KEY_UID = "uid_tag_int";
- private static final String KEY_COUNTER_SET = "cnt_set";
- private static final String KEY_TAG_HEX = "acct_tag_hex";
- private static final String KEY_SNAP_RX_BYTES = "snap_rx_bytes";
- private static final String KEY_SNAP_RX_PACKETS = "snap_rx_packets";
- private static final String KEY_SNAP_TX_BYTES = "snap_tx_bytes";
- private static final String KEY_SNAP_TX_PACKETS = "snap_tx_packets";
- private static final String KEY_RX_BYTES = "rx_bytes";
- private static final String KEY_RX_PACKETS = "rx_packets";
- private static final String KEY_TX_BYTES = "tx_bytes";
- private static final String KEY_TX_PACKETS = "tx_packets";
-
class NetdResponseCode {
/* Keep in sync with system/netd/ResponseCode.h */
public static final int InterfaceListResult = 110;
@@ -156,6 +119,8 @@
// TODO: replace with RemoteCallbackList
private ArrayList<INetworkManagementEventObserver> mObservers;
+ private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
+
private Object mQuotaLock = new Object();
/** Set of interfaces with active quotas. */
private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
@@ -171,16 +136,10 @@
*
* @param context Binder context for this service
*/
- private NetworkManagementService(Context context, File procRoot) {
+ private NetworkManagementService(Context context) {
mContext = context;
mObservers = new ArrayList<INetworkManagementEventObserver>();
- mStatsUid = new File(procRoot, "uid_stat");
- mStatsIface = new File(procRoot, "net/dev");
- mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
- mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
- mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
-
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
return;
}
@@ -194,8 +153,7 @@
}
public static NetworkManagementService create(Context context) throws InterruptedException {
- NetworkManagementService service = new NetworkManagementService(
- context, new File("/proc/"));
+ NetworkManagementService service = new NetworkManagementService(context);
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
service.mThread.start();
if (DBG) Slog.d(TAG, "Awaiting socket connection");
@@ -204,15 +162,6 @@
return service;
}
- // @VisibleForTesting
- public static NetworkManagementService createForTest(
- Context context, File procRoot, boolean bandwidthControlEnabled) {
- // TODO: eventually connect with mock netd
- final NetworkManagementService service = new NetworkManagementService(context, procRoot);
- service.mBandwidthControlEnabled = bandwidthControlEnabled;
- return service;
- }
-
public void systemReady() {
// only enable bandwidth control when support exists, and requested by
// system setting.
@@ -226,7 +175,7 @@
mConnector.doCommand("bandwidth enable");
mBandwidthControlEnabled = true;
} catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "problem enabling bandwidth controls", e);
+ Log.wtf(TAG, "problem enabling bandwidth controls", e);
}
} else {
Slog.d(TAG, "not enabling bandwidth control");
@@ -1081,165 +1030,14 @@
public NetworkStats getNetworkStatsSummary() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
-
- if (mBandwidthControlEnabled && mStatsXtIfaceAll.exists()) {
- return getNetworkStatsSummarySingleFile();
- } else {
- return getNetworkStatsSummaryMultipleFiles();
- }
- }
-
- @Deprecated
- private NetworkStats getNetworkStatsSummaryMultipleFiles() {
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
-
- final HashSet<String> knownIfaces = Sets.newHashSet();
- final HashSet<String> activeIfaces = Sets.newHashSet();
-
- // collect any historical stats and active state
- // TODO: migrate to reading from single file
- if (mBandwidthControlEnabled) {
- for (String iface : fileListWithoutNull(mStatsXtIface)) {
- final File ifacePath = new File(mStatsXtIface, iface);
-
- final long active = readSingleLongFromFile(new File(ifacePath, "active"));
- if (active == 1) {
- knownIfaces.add(iface);
- activeIfaces.add(iface);
- } else if (active == 0) {
- knownIfaces.add(iface);
- } else {
- continue;
- }
-
- entry.iface = iface;
- entry.uid = UID_ALL;
- entry.set = SET_DEFAULT;
- entry.tag = TAG_NONE;
- entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
- entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
- entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
- entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
-
- stats.addValues(entry);
- }
- }
-
- final ArrayList<String> values = Lists.newArrayList();
-
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new FileReader(mStatsIface));
-
- // skip first two header lines
- reader.readLine();
- reader.readLine();
-
- // parse remaining lines
- String line;
- while ((line = reader.readLine()) != null) {
- splitLine(line, values);
-
- try {
- entry.iface = values.get(0);
- entry.uid = UID_ALL;
- entry.set = SET_DEFAULT;
- entry.tag = TAG_NONE;
- entry.rxBytes = Long.parseLong(values.get(1));
- entry.rxPackets = Long.parseLong(values.get(2));
- entry.txBytes = Long.parseLong(values.get(9));
- entry.txPackets = Long.parseLong(values.get(10));
-
- if (activeIfaces.contains(entry.iface)) {
- // combine stats when iface is active
- stats.combineValues(entry);
- } else if (!knownIfaces.contains(entry.iface)) {
- // add stats when iface is unknown
- stats.addValues(entry);
- }
- } catch (NumberFormatException e) {
- Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
- }
- }
- } catch (NullPointerException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
- } catch (NumberFormatException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
- } catch (IOException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
- } finally {
- IoUtils.closeQuietly(reader);
- }
-
- return stats;
- }
-
- private NetworkStats getNetworkStatsSummarySingleFile() {
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
-
- // TODO: read directly from proc once headers are added
- final ArrayList<String> keys = Lists.newArrayList(KEY_IFACE, KEY_ACTIVE, KEY_SNAP_RX_BYTES,
- KEY_SNAP_RX_PACKETS, KEY_SNAP_TX_BYTES, KEY_SNAP_TX_PACKETS, KEY_RX_BYTES,
- KEY_RX_PACKETS, KEY_TX_BYTES, KEY_TX_PACKETS);
- final ArrayList<String> values = Lists.newArrayList();
- final HashMap<String, String> parsed = Maps.newHashMap();
-
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new FileReader(mStatsXtIfaceAll));
-
- String line;
- while ((line = reader.readLine()) != null) {
- splitLine(line, values);
- parseLine(keys, values, parsed);
-
- entry.iface = parsed.get(KEY_IFACE);
- entry.uid = UID_ALL;
- entry.set = SET_DEFAULT;
- entry.tag = TAG_NONE;
-
- // always include snapshot values
- entry.rxBytes = getParsedLong(parsed, KEY_SNAP_RX_BYTES);
- entry.rxPackets = getParsedLong(parsed, KEY_SNAP_RX_PACKETS);
- entry.txBytes = getParsedLong(parsed, KEY_SNAP_TX_BYTES);
- entry.txPackets = getParsedLong(parsed, KEY_SNAP_TX_PACKETS);
-
- // fold in active numbers, but only when active
- final boolean active = getParsedInt(parsed, KEY_ACTIVE) != 0;
- if (active) {
- entry.rxBytes += getParsedLong(parsed, KEY_RX_BYTES);
- entry.rxPackets += getParsedLong(parsed, KEY_RX_PACKETS);
- entry.txBytes += getParsedLong(parsed, KEY_TX_BYTES);
- entry.txPackets += getParsedLong(parsed, KEY_TX_PACKETS);
- }
-
- stats.addValues(entry);
- }
- } catch (NullPointerException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
- } catch (NumberFormatException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
- } catch (IOException e) {
- throw new IllegalStateException("problem parsing stats: " + e);
- } finally {
- IoUtils.closeQuietly(reader);
- }
-
- return stats;
+ return mStatsFactory.readNetworkStatsSummary();
}
@Override
public NetworkStats getNetworkStatsDetail() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
-
- if (mBandwidthControlEnabled) {
- return getNetworkStatsDetailNetfilter(UID_ALL);
- } else {
- return getNetworkStatsDetailUidstat(UID_ALL);
- }
+ return mStatsFactory.readNetworkStatsDetail(UID_ALL);
}
@Override
@@ -1422,126 +1220,7 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
}
-
- if (mBandwidthControlEnabled) {
- return getNetworkStatsDetailNetfilter(uid);
- } else {
- return getNetworkStatsDetailUidstat(uid);
- }
- }
-
- /**
- * Build {@link NetworkStats} with detailed UID statistics.
- */
- private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
-
- // TODO: remove knownLines check once 5087722 verified
- final HashSet<String> knownLines = Sets.newHashSet();
- // TODO: remove lastIdx check once 5270106 verified
- int lastIdx;
-
- final ArrayList<String> keys = Lists.newArrayList();
- final ArrayList<String> values = Lists.newArrayList();
- final HashMap<String, String> parsed = Maps.newHashMap();
-
- BufferedReader reader = null;
- String line = null;
- try {
- reader = new BufferedReader(new FileReader(mStatsXtUid));
-
- // parse first line as header
- line = reader.readLine();
- splitLine(line, keys);
- lastIdx = 1;
-
- // parse remaining lines
- while ((line = reader.readLine()) != null) {
- splitLine(line, values);
- parseLine(keys, values, parsed);
-
- if (!knownLines.add(line)) {
- throw new IllegalStateException("duplicate proc entry: " + line);
- }
-
- final int idx = getParsedInt(parsed, KEY_IDX);
- if (idx != lastIdx + 1) {
- throw new IllegalStateException(
- "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
- }
- lastIdx = idx;
-
- entry.iface = parsed.get(KEY_IFACE);
- entry.uid = getParsedInt(parsed, KEY_UID);
- entry.set = getParsedInt(parsed, KEY_COUNTER_SET);
- entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
- entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
- entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
- entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
- entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
-
- if (limitUid == UID_ALL || limitUid == entry.uid) {
- stats.addValues(entry);
- }
- }
- } catch (NullPointerException e) {
- throw new IllegalStateException("problem parsing line: " + line, e);
- } catch (NumberFormatException e) {
- throw new IllegalStateException("problem parsing line: " + line, e);
- } catch (IOException e) {
- throw new IllegalStateException("problem parsing line: " + line, e);
- } finally {
- IoUtils.closeQuietly(reader);
- }
-
- return stats;
- }
-
- private static int getParsedInt(HashMap<String, String> parsed, String key) {
- final String value = parsed.get(key);
- return value != null ? Integer.parseInt(value) : 0;
- }
-
- private static long getParsedLong(HashMap<String, String> parsed, String key) {
- final String value = parsed.get(key);
- return value != null ? Long.parseLong(value) : 0;
- }
-
- /**
- * Build {@link NetworkStats} with detailed UID statistics.
- *
- * @deprecated since this uses older "uid_stat" data, and doesn't provide
- * tag-level granularity or additional variables.
- */
- @Deprecated
- private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
- final String[] knownUids;
- if (limitUid == UID_ALL) {
- knownUids = fileListWithoutNull(mStatsUid);
- } else {
- knownUids = new String[] { String.valueOf(limitUid) };
- }
-
- final NetworkStats stats = new NetworkStats(
- SystemClock.elapsedRealtime(), knownUids.length);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- for (String uid : knownUids) {
- final int uidInt = Integer.parseInt(uid);
- final File uidPath = new File(mStatsUid, uid);
-
- entry.iface = IFACE_ALL;
- entry.uid = uidInt;
- entry.tag = TAG_NONE;
- entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
- entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
- entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
- entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
-
- stats.addValues(entry);
- }
-
- return stats;
+ return mStatsFactory.readNetworkStatsDetail(uid);
}
@Override
@@ -1670,56 +1349,6 @@
return getInterfaceThrottle(iface, false);
}
- /**
- * Split given line into {@link ArrayList}.
- */
- private static void splitLine(String line, ArrayList<String> outSplit) {
- outSplit.clear();
-
- final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
- while (t.hasMoreTokens()) {
- outSplit.add(t.nextToken());
- }
- }
-
- /**
- * Zip the two given {@link ArrayList} as key and value pairs into
- * {@link HashMap}.
- */
- private static void parseLine(
- ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
- outParsed.clear();
-
- final int size = Math.min(keys.size(), values.size());
- for (int i = 0; i < size; i++) {
- outParsed.put(keys.get(i), values.get(i));
- }
- }
-
- /**
- * Utility method to read a single plain-text {@link Long} from the given
- * {@link File}, usually from a {@code /proc/} filesystem.
- */
- private static long readSingleLongFromFile(File file) {
- try {
- final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
- return Long.parseLong(new String(buffer).trim());
- } catch (NumberFormatException e) {
- return -1;
- } catch (IOException e) {
- return -1;
- }
- }
-
- /**
- * Wrapper for {@link File#list()} that returns empty array instead of
- * {@code null}.
- */
- private static String[] fileListWithoutNull(File file) {
- final String[] list = file.list();
- return list != null ? list : new String[0];
- }
-
public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index bab9f8a..a9ff6c5 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -117,11 +117,6 @@
// ================================================================================
// From IStatusBarService
// ================================================================================
- public void userActivity() {
- if (mBar != null) try {
- mBar.userActivity();
- } catch (RemoteException ex) {}
- }
public void expand() {
enforceExpandStatusBar();
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 253e741..a0e28ed 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -834,7 +834,7 @@
}
if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
if (success) {
- bindWallpaperComponentLocked(null, false, false);
+ bindWallpaperComponentLocked(mNextWallpaperComponent, false, false);
}
}
}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index b44dc8a2..8f797ec 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -417,6 +417,13 @@
}
}
+ public void noteNetworkInterfaceType(String iface, int type) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteNetworkInterfaceTypeLocked(iface, type);
+ }
+ }
+
public boolean isOnBattery() {
return mStats.isOnBattery();
}
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index f2e7485..25cc259 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -32,7 +32,6 @@
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
import java.util.ArrayList;
diff --git a/services/java/com/android/server/wm/FakeWindowImpl.java b/services/java/com/android/server/wm/FakeWindowImpl.java
new file mode 100644
index 0000000..0e72f7d
--- /dev/null
+++ b/services/java/com/android/server/wm/FakeWindowImpl.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.os.Looper;
+import android.os.Process;
+import android.util.Slog;
+import android.view.InputChannel;
+import android.view.InputHandler;
+import android.view.InputQueue;
+import android.view.WindowManagerPolicy;
+
+public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow {
+ final WindowManagerService mService;
+ final InputChannel mServerChannel, mClientChannel;
+ final InputApplicationHandle mApplicationHandle;
+ final InputWindowHandle mWindowHandle;
+ final int mWindowLayer;
+
+ boolean mTouchFullscreen;
+
+ public FakeWindowImpl(WindowManagerService service, Looper looper, InputHandler inputHandler,
+ String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
+ boolean hasFocus, boolean touchFullscreen) {
+ mService = service;
+
+ InputChannel[] channels = InputChannel.openInputChannelPair(name);
+ mServerChannel = channels[0];
+ mClientChannel = channels[1];
+ mService.mInputManager.registerInputChannel(mServerChannel, null);
+ InputQueue.registerInputChannel(mClientChannel, inputHandler, looper.getQueue());
+
+ mApplicationHandle = new InputApplicationHandle(null);
+ mApplicationHandle.name = name;
+ mApplicationHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+
+ mWindowHandle = new InputWindowHandle(mApplicationHandle, null);
+ mWindowHandle.name = name;
+ mWindowHandle.inputChannel = mServerChannel;
+ mWindowLayer = getLayerLw(windowType);
+ mWindowHandle.layer = mWindowLayer;
+ mWindowHandle.layoutParamsFlags = layoutParamsFlags;
+ mWindowHandle.layoutParamsType = windowType;
+ mWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mWindowHandle.visible = true;
+ mWindowHandle.canReceiveKeys = canReceiveKeys;
+ mWindowHandle.hasFocus = hasFocus;
+ mWindowHandle.hasWallpaper = false;
+ mWindowHandle.paused = false;
+ mWindowHandle.ownerPid = Process.myPid();
+ mWindowHandle.ownerUid = Process.myUid();
+ mWindowHandle.inputFeatures = 0;
+ mWindowHandle.scaleFactor = 1.0f;
+
+ mTouchFullscreen = touchFullscreen;
+ }
+
+ void layout(int dw, int dh) {
+ if (mTouchFullscreen) {
+ mWindowHandle.touchableRegion.set(0, 0, dw, dh);
+ } else {
+ mWindowHandle.touchableRegion.setEmpty();
+ }
+ mWindowHandle.frameLeft = 0;
+ mWindowHandle.frameTop = 0;
+ mWindowHandle.frameRight = dw;
+ mWindowHandle.frameBottom = dh;
+ }
+
+ @Override
+ public void dismiss() {
+ synchronized (mService.mWindowMap) {
+ if (mService.removeFakeWindowLocked(this)) {
+ mService.mInputManager.unregisterInputChannel(mServerChannel);
+ InputQueue.unregisterInputChannel(mClientChannel);
+ mClientChannel.dispose();
+ mServerChannel.dispose();
+ }
+ }
+ }
+
+ private int getLayerLw(int windowType) {
+ return mService.mPolicy.windowTypeToLayerLw(windowType)
+ * WindowManagerService.TYPE_LAYER_MULTIPLIER
+ + WindowManagerService.TYPE_LAYER_OFFSET;
+ }
+}
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 573a7d42..9a559e0 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -169,6 +169,11 @@
}
}
+ final int NFW = mService.mFakeWindows.size();
+ for (int i = 0; i < NFW; i++) {
+ addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle);
+ }
+
final int N = windows.size();
for (int i = N - 1; i >= 0; i--) {
final WindowState child = windows.get(i);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 540c518..73a9601 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -118,6 +118,7 @@
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy.FakeWindow;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
@@ -142,7 +143,7 @@
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
- implements Watchdog.Monitor {
+ implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
@@ -352,6 +353,12 @@
final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();
/**
+ * Fake windows added to the window manager. Note: ordered from top to
+ * bottom, opposite of mWindows.
+ */
+ final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>();
+
+ /**
* Windows that are being resized. Used so we can tell the client about
* the resize after closing the transaction in which we resized the
* underlying surface.
@@ -442,7 +449,9 @@
int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
int mLayoutSeq = 0;
-
+
+ int mLastStatusBarVisibility = 0;
+
// State while inside of layoutAndPlaceSurfacesLocked().
boolean mFocusMayChange;
@@ -702,7 +711,7 @@
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
- mPolicy.init(mContext, mService, mPM);
+ mPolicy.init(mContext, mService, mService, mPM);
synchronized (this) {
mRunning = true;
@@ -6368,8 +6377,6 @@
// Ignore if process has died.
}
}
-
- mPolicy.focusChanged(lastFocus, newFocus);
}
} break;
@@ -7184,6 +7191,11 @@
final int dw = mCurDisplayWidth;
final int dh = mCurDisplayHeight;
+ final int NFW = mFakeWindows.size();
+ for (int i=0; i<NFW; i++) {
+ mFakeWindows.get(i).layout(dw, dh);
+ }
+
final int N = mWindows.size();
int i;
@@ -8835,6 +8847,7 @@
final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
+ int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
final WindowState imWindow = mInputMethodWindow;
if (newFocus != imWindow && oldFocus != imWindow) {
@@ -8845,13 +8858,22 @@
}
if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
performLayoutLockedInner(true /*initial*/, updateInputWindows);
+ focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
} else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
// Client will do the layout, but we need to assign layers
// for handleNewWindowLocked() below.
assignLayersLocked();
}
}
-
+
+ if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+ // The change in focus caused us to need to do a layout. Okay.
+ mLayoutNeeded = true;
+ if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
+ performLayoutLockedInner(true /*initial*/, updateInputWindows);
+ }
+ }
+
if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
// If we defer assigning layers, then the caller is responsible for
// doing this part.
@@ -9097,33 +9119,82 @@
@Override
public void statusBarVisibilityChanged(int visibility) {
- mInputManager.setSystemUiVisibility(visibility);
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Caller does not hold permission "
+ + android.Manifest.permission.STATUS_BAR);
+ }
synchronized (mWindowMap) {
- final int N = mWindows.size();
- for (int i = 0; i < N; i++) {
- WindowState ws = mWindows.get(i);
- try {
- int curValue = ws.mSystemUiVisibility;
- int diff = curValue ^ visibility;
- // We are only interested in differences of one of the
- // clearable flags...
- diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
- // ...if it has actually been cleared.
- diff &= ~visibility;
- int newValue = (curValue&~diff) | (visibility&diff);
- if (newValue != curValue) {
- ws.mSeq++;
- ws.mSystemUiVisibility = newValue;
- }
- if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
- ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
- visibility, newValue, diff);
- }
- } catch (RemoteException e) {
- // so sorry
+ mLastStatusBarVisibility = visibility;
+ visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
+ updateStatusBarVisibilityLocked(visibility);
+ }
+ }
+
+ void updateStatusBarVisibilityLocked(int visibility) {
+ mInputManager.setSystemUiVisibility(visibility);
+ final int N = mWindows.size();
+ for (int i = 0; i < N; i++) {
+ WindowState ws = mWindows.get(i);
+ try {
+ int curValue = ws.mSystemUiVisibility;
+ int diff = curValue ^ visibility;
+ // We are only interested in differences of one of the
+ // clearable flags...
+ diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
+ // ...if it has actually been cleared.
+ diff &= ~visibility;
+ int newValue = (curValue&~diff) | (visibility&diff);
+ if (newValue != curValue) {
+ ws.mSeq++;
+ ws.mSystemUiVisibility = newValue;
+ }
+ if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
+ ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
+ visibility, newValue, diff);
+ }
+ } catch (RemoteException e) {
+ // so sorry
+ }
+ }
+ }
+
+ @Override
+ public void reevaluateStatusBarVisibility() {
+ synchronized (mWindowMap) {
+ int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
+ updateStatusBarVisibilityLocked(visibility);
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+
+ @Override
+ public FakeWindow addFakeWindow(Looper looper, InputHandler inputHandler,
+ String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
+ boolean hasFocus, boolean touchFullscreen) {
+ synchronized (mWindowMap) {
+ FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputHandler, name, windowType,
+ layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
+ int i=0;
+ while (i<mFakeWindows.size()) {
+ if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
+ break;
}
}
+ mFakeWindows.add(i, fw);
+ mInputMonitor.updateInputWindowsLw(true);
+ return fw;
+ }
+ }
+
+ boolean removeFakeWindowLocked(FakeWindow window) {
+ synchronized (mWindowMap) {
+ if (mFakeWindows.remove(window)) {
+ mInputMonitor.updateInputWindowsLw(true);
+ return true;
+ }
+ return false;
}
}
@@ -9387,6 +9458,10 @@
pw.print(" mInTouchMode="); pw.print(mInTouchMode);
pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
if (dumpAll) {
+ if (mLastStatusBarVisibility != 0) {
+ pw.print(" mLastStatusBarVisibility=0x");
+ pw.println(Integer.toHexString(mLastStatusBarVisibility));
+ }
if (mInputMethodWindow != null) {
pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow);
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 41d7a90..feb2c52 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -280,20 +280,29 @@
return;
}
- const GLenum target = GL_TEXTURE_EXTERNAL_OES;
- glBindTexture(target, mTextureName);
- if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
- // TODO: we could be more subtle with isFixedSize()
- glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ GLenum target = GL_TEXTURE_EXTERNAL_OES;
+ if (!isProtected()) {
+ glBindTexture(target, mTextureName);
+ if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
+ // TODO: we could be more subtle with isFixedSize()
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ glEnable(target);
+ glMatrixMode(GL_TEXTURE);
+ glLoadMatrixf(mTextureMatrix);
+ glMatrixMode(GL_MODELVIEW);
} else {
- glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ target = GL_TEXTURE_2D;
+ glBindTexture(target, mFlinger->getProtectedTexName());
+ glEnable(target);
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
}
- glEnable(target);
- glMatrixMode(GL_TEXTURE);
- glLoadMatrixf(mTextureMatrix);
- glMatrixMode(GL_MODELVIEW);
drawWithOpenGL(clip);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3f154ce..b01a6a3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -275,7 +275,7 @@
const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
const uint16_t g1 = pack565(0x17,0x2f,0x17);
- const uint16_t textureData[4] = { g0, g1, g1, g0 };
+ const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };
glGenTextures(1, &mWormholeTexName);
glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -283,7 +283,17 @@
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData);
+
+ const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) };
+ glGenTextures(1, &mProtectedTexName);
+ glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
+ GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
@@ -2255,22 +2265,6 @@
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
return BAD_VALUE;
- // make sure none of the layers are protected
- const LayerVector& layers(mDrawingState.layersSortedByZ);
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(layers[i]);
- const uint32_t flags = layer->drawingState().flags;
- if (!(flags & ISurfaceComposer::eLayerHidden)) {
- const uint32_t z = layer->drawingState().z;
- if (z >= minLayerZ && z <= maxLayerZ) {
- if (layer->isProtected()) {
- return INVALID_OPERATION;
- }
- }
- }
- }
-
if (!GLExtensions::getInstance().haveFramebufferObject())
return INVALID_OPERATION;
@@ -2320,6 +2314,8 @@
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
const uint32_t flags = layer->drawingState().flags;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 128a64d..92b265e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -192,6 +192,8 @@
sp<Layer> getLayer(const sp<ISurface>& sur) const;
+ GLuint getProtectedTexName() const { return mProtectedTexName; }
+
private:
// DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
@@ -349,6 +351,7 @@
sp<IMemoryHeap> mServerHeap;
surface_flinger_cblk_t* mServerCblk;
GLuint mWormholeTexName;
+ GLuint mProtectedTexName;
nsecs_t mBootTime;
// Can only accessed from the main thread, these members