Merge "temporarily skip simple-cross-origin-progress-events.html for now"
diff --git a/api/current.xml b/api/current.xml
index eb21d97..615cd93 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -16482,6 +16482,50 @@
visibility="public"
>
</field>
+<field name="TextAppearance_StatusBar_EventContent"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973927"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TextAppearance_StatusBar_EventContent_Title"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973928"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TextAppearance_StatusBar_Icon"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973926"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TextAppearance_StatusBar_Title"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973925"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="TextAppearance_Theme"
type="int"
transient="false"
@@ -17824,50 +17868,6 @@
visibility="public"
>
</field>
-<field name="kraken_resource_pad41"
- type="int"
- transient="false"
- volatile="false"
- value="16973928"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad42"
- type="int"
- transient="false"
- volatile="false"
- value="16973927"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad43"
- type="int"
- transient="false"
- volatile="false"
- value="16973926"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="kraken_resource_pad44"
- type="int"
- transient="false"
- volatile="false"
- value="16973925"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="kraken_resource_pad5"
type="int"
transient="false"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 2e87394..f6f80d1 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -136,7 +136,7 @@
/* TODO(oam): depending on use case (ecryptfs or dmcrypt)
* change implementation
*/
-static int disk_free()
+static int64_t disk_free()
{
struct statfs sfs;
if (statfs(PKG_DIR_PREFIX, &sfs) == 0) {
@@ -154,18 +154,18 @@
* also require that apps constantly modify file metadata even
* when just reading from the cache, which is pretty awful.
*/
-int free_cache(int free_size)
+int free_cache(int64_t free_size)
{
const char *name;
int dfd, subfd;
DIR *d;
struct dirent *de;
- int avail;
+ int64_t avail;
avail = disk_free();
if (avail < 0) return -1;
- LOGI("free_cache(%d) avail %d\n", free_size, avail);
+ LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
if (avail >= free_size) return 0;
/* First try encrypted dir */
@@ -327,10 +327,10 @@
return 0;
}
-static int stat_size(struct stat *s)
+static int64_t stat_size(struct stat *s)
{
- int blksize = s->st_blksize;
- int size = s->st_size;
+ int64_t blksize = s->st_blksize;
+ int64_t size = s->st_size;
if (blksize) {
/* round up to filesystem block size */
@@ -340,9 +340,9 @@
return size;
}
-static int calculate_dir_size(int dfd)
+static int64_t calculate_dir_size(int dfd)
{
- int size = 0;
+ int64_t size = 0;
struct stat s;
DIR *d;
struct dirent *de;
@@ -378,7 +378,7 @@
int get_size(const char *pkgname, const char *apkpath,
const char *fwdlock_apkpath,
- int *_codesize, int *_datasize, int *_cachesize, int encrypted_fs_flag)
+ int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize, int encrypted_fs_flag)
{
DIR *d;
int dfd;
@@ -386,9 +386,9 @@
struct stat s;
char path[PKG_PATH_MAX];
- int codesize = 0;
- int datasize = 0;
- int cachesize = 0;
+ int64_t codesize = 0;
+ int64_t datasize = 0;
+ int64_t cachesize = 0;
/* count the source apk as code -- but only if it's not
* on the /system partition and its not on the sdcard.
@@ -445,7 +445,7 @@
}
subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
if (subfd >= 0) {
- int size = calculate_dir_size(subfd);
+ int64_t size = calculate_dir_size(subfd);
if (!strcmp(name,"lib")) {
codesize += size;
} else if(!strcmp(name,"cache")) {
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 882c493..c991845 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -60,7 +60,7 @@
static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
{
- return free_cache(atoi(arg[0])); /* free_size */
+ return free_cache((int64_t)atoll(arg[0])); /* free_size */
}
static int do_rm_cache(char **arg, char reply[REPLY_MAX])
@@ -75,15 +75,19 @@
static int do_get_size(char **arg, char reply[REPLY_MAX])
{
- int codesize = 0;
- int datasize = 0;
- int cachesize = 0;
+ int64_t codesize = 0;
+ int64_t datasize = 0;
+ int64_t cachesize = 0;
int res = 0;
/* pkgdir, apkpath */
res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize, atoi(arg[3]));
- sprintf(reply,"%d %d %d", codesize, datasize, cachesize);
+ /*
+ * Each int64_t can take up 22 characters printed out. Make sure it
+ * doesn't go over REPLY_MAX in the future.
+ */
+ snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64, codesize, datasize, cachesize);
return res;
}
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 8e4adb1..479e4b2 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -19,6 +19,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
@@ -105,7 +107,7 @@
int rm_dex(const char *path);
int protect(char *pkgname, gid_t gid);
int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath,
- int *codesize, int *datasize, int *cachesize, int encrypted_fs_flag);
-int free_cache(int free_size);
+ int64_t *codesize, int64_t *datasize, int64_t *cachesize, int encrypted_fs_flag);
+int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 4dc88b3..d7a0412 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -3,8 +3,6 @@
import com.android.internal.view.IInputMethodCallback;
import com.android.internal.view.IInputMethodSession;
-import dalvik.system.PathClassLoader;
-
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -168,17 +166,14 @@
// If the application does not have (Java) code, then no ClassLoader
// has been set up for it. We will need to do our own search for
// the native code.
- path = ai.applicationInfo.dataDir + "/lib/" + System.mapLibraryName(libname);
- if (!(new File(path)).exists()) {
- path = null;
+ File libraryFile = new File(ai.applicationInfo.nativeLibraryDir,
+ System.mapLibraryName(libname));
+ if (libraryFile.exists()) {
+ path = libraryFile.getPath();
}
}
if (path == null) {
- path = ((PathClassLoader)getClassLoader()).findLibrary(libname);
- }
-
- if (path == null) {
throw new IllegalArgumentException("Unable to find native library: " + libname);
}
diff --git a/core/java/android/app/backup/SharedPreferencesBackupHelper.java b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
index 23b1703..213bd31 100644
--- a/core/java/android/app/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.app.QueuedWork;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.ParcelFileDescriptor;
@@ -94,7 +95,11 @@
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
Context context = mContext;
-
+
+ // If a SharedPreference has an outstanding write in flight,
+ // wait for it to finish flushing to disk.
+ QueuedWork.waitToFinish();
+
// make filenames for the prefGroups
String[] prefGroups = mPrefGroups;
final int N = prefGroups.length;
@@ -123,4 +128,3 @@
}
}
}
-
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index aa0a57d..9541380 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -144,6 +144,22 @@
}
}
+ @Override public String toString() {
+ synchronized(this) {
+ StringBuilder buff = new StringBuilder();
+ buff.append(" nStatement=");
+ buff.append(nStatement);
+ buff.append(", db=");
+ buff.append(mDatabase.getPath());
+ buff.append(", db_connectionNum=");
+ buff.append(mDatabase.mConnectionNum);
+ buff.append(", sql=");
+ int len = mSqlStmt.length();
+ buff.append(mSqlStmt.substring(0, (len > 100) ? 100 : len));
+ return buff.toString();
+ }
+ }
+
/**
* Compiles SQL into a SQLite program.
*
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0137ea6..6937da0 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1066,7 +1066,7 @@
closePendingStatements();
releaseCustomFunctions();
// close this database instance - regardless of its reference count value
- dbclose();
+ closeDatabase();
if (mConnectionPool != null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
assert mConnectionPool != null;
@@ -1075,7 +1075,7 @@
mConnectionPool.close();
}
} finally {
- unlock();
+ unlock();
}
}
@@ -1100,6 +1100,47 @@
}
/**
+ * package level access for testing purposes
+ */
+ /* package */ void closeDatabase() throws SQLiteException {
+ try {
+ dbclose();
+ } catch (SQLiteUnfinalizedObjectsException e) {
+ String msg = e.getMessage();
+ String[] tokens = msg.split(",", 2);
+ int stmtId = Integer.parseInt(tokens[0]);
+ // get extra info about this statement, if it is still to be released by closeClosable()
+ Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
+ boolean found = false;
+ while (iter.hasNext()) {
+ Map.Entry<SQLiteClosable, Object> entry = iter.next();
+ SQLiteClosable program = entry.getKey();
+ if (program != null && program instanceof SQLiteProgram) {
+ SQLiteCompiledSql compiledSql = ((SQLiteProgram)program).mCompiledSql;
+ if (compiledSql.nStatement == stmtId) {
+ msg = compiledSql.toString();
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ // the statement is already released by closeClosable(). is it waiting to be
+ // finalized?
+ if (mClosedStatementIds.contains(stmtId)) {
+ Log.w(TAG, "this shouldn't happen. finalizing the statement now: ");
+ closePendingStatements();
+ // try to close the database again
+ closeDatabase();
+ }
+ } else {
+ // the statement is not yet closed. most probably programming error in the app.
+ Log.w(TAG, "dbclose failed due to un-close()d SQL statements: " + msg);
+ throw e;
+ }
+ }
+ }
+
+ /**
* Native call to close the database.
*/
private native void dbclose();
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 9b7d823..5e08aed 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -52,7 +52,7 @@
/**
* the SQLiteCompiledSql object for the given sql statement.
*/
- private SQLiteCompiledSql mCompiledSql;
+ /* package */ SQLiteCompiledSql mCompiledSql;
/**
* SQLiteCompiledSql statement id is populated with the corresponding object from the above
diff --git a/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java b/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java
new file mode 100644
index 0000000..bcf95e2
--- /dev/null
+++ b/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite;
+
+/**
+ * Thrown if the database can't be closed because of some un-closed
+ * Cursor or SQLiteStatement objects. Could happen when a thread is trying to close
+ * the database while another thread still hasn't closed a Cursor on that database.
+ * @hide
+ */
+public class SQLiteUnfinalizedObjectsException extends SQLiteException {
+ public SQLiteUnfinalizedObjectsException() {}
+
+ public SQLiteUnfinalizedObjectsException(String error) {
+ super(error);
+ }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 9fe6e01..a857e58 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -216,6 +216,11 @@
public abstract Map<Integer, ? extends Sensor> getSensorStats();
/**
+ * Returns a mapping containing active process data.
+ */
+ public abstract SparseArray<? extends Pid> getPidStats();
+
+ /**
* Returns a mapping containing process statistics.
*
* @return a Map from Strings to Uid.Proc objects.
@@ -286,6 +291,11 @@
public abstract Timer getSensorTime();
}
+ public class Pid {
+ public long mWakeSum;
+ public long mWakeStart;
+ }
+
/**
* The statistics associated with a particular process.
*/
@@ -521,6 +531,11 @@
public abstract HistoryItem getHistory();
/**
+ * Return the base time offset for the battery history.
+ */
+ public abstract long getHistoryBaseTime();
+
+ /**
* Returns the number of times the device has been started.
*/
public abstract int getStartCount();
@@ -1673,6 +1688,7 @@
HistoryItem rec = getHistory();
if (rec != null) {
pw.println("Battery History:");
+ long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
int oldState = 0;
int oldStatus = -1;
int oldHealth = -1;
@@ -1681,7 +1697,7 @@
int oldVolt = -1;
while (rec != null) {
pw.print(" ");
- pw.print(rec.time);
+ TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
pw.print(" ");
if (rec.cmd == HistoryItem.CMD_START) {
pw.println(" START");
@@ -1784,6 +1800,35 @@
oldState = rec.states;
rec = rec.next;
}
+ pw.println("");
+ }
+
+ SparseArray<? extends Uid> uidStats = getUidStats();
+ final int NU = uidStats.size();
+ boolean didPid = false;
+ long nowRealtime = SystemClock.elapsedRealtime();
+ StringBuilder sb = new StringBuilder(64);
+ for (int i=0; i<NU; i++) {
+ Uid uid = uidStats.valueAt(i);
+ SparseArray<? extends Uid.Pid> pids = uid.getPidStats();
+ if (pids != null) {
+ for (int j=0; j<pids.size(); j++) {
+ Uid.Pid pid = pids.valueAt(j);
+ if (!didPid) {
+ pw.println("Per-PID Stats:");
+ didPid = true;
+ }
+ long time = pid.mWakeSum + (pid.mWakeStart != 0
+ ? (nowRealtime - pid.mWakeStart) : 0);
+ pw.print(" PID "); pw.print(pids.keyAt(j));
+ pw.print(" wake time: ");
+ TimeUtils.formatDuration(time, pw);
+ pw.println("");
+ }
+ }
+ }
+ if (didPid) {
+ pw.println("");
}
pw.println("Statistics since last charge:");
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 3fe14f9..0408673 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -34,7 +34,7 @@
* An optional controller for the cursor.
* Use {@link #setCursorController(CursorController)} to set this field.
*/
- protected CursorController mCursorController;
+ private CursorController mCursorController;
private boolean isCap(Spannable buffer) {
return ((MetaKeyKeyListener.getMetaState(buffer, KeyEvent.META_SHIFT_ON) == 1) ||
@@ -302,7 +302,17 @@
/**
* Defines the cursor controller.
*
- * When set, this object can be used to handle events, that can be translated in cursor updates.
+ * When set, this object can be used to handle touch events, that can be translated into cursor
+ * updates.
+ *
+ * {@link MotionEvent#ACTION_MOVE} events will call back the
+ * {@link CursorController#updatePosition(int, int)} controller's method, passing the current
+ * finger coordinates (offset by {@link CursorController#getOffsetX()} and
+ * {@link CursorController#getOffsetY()}) as parameters.
+ *
+ * When the gesture is finished (on a {@link MotionEvent#ACTION_UP} or
+ * {@link MotionEvent#ACTION_CANCEL} event), the controller is reset to null.
+ *
* @param cursorController A cursor controller implementation
*/
public void setCursorController(CursorController cursorController) {
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index b01a71d..60ca384 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -132,20 +132,76 @@
return ZoneInfoDB.getVersion();
}
+ /** @hide Field length that can hold 999 days of time */
+ public static final int HUNDRED_DAY_FIELD_LEN = 19;
+
private static final int SECONDS_PER_MINUTE = 60;
private static final int SECONDS_PER_HOUR = 60 * 60;
private static final int SECONDS_PER_DAY = 24 * 60 * 60;
- /** @hide Just for debugging; not internationalized. */
- public static void formatDuration(long duration, StringBuilder builder) {
- if (duration == 0) {
- builder.append("0");
- return;
+ private static final Object sFormatSync = new Object();
+ private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5];
+
+ static private int accumField(int amt, int suffix, boolean always, int zeropad) {
+ if (amt > 99 || (always && zeropad >= 3)) {
+ return 3+suffix;
}
+ if (amt > 9 || (always && zeropad >= 2)) {
+ return 2+suffix;
+ }
+ if (always || amt > 0) {
+ return 1+suffix;
+ }
+ return 0;
+ }
+
+ static private int printField(char[] formatStr, int amt, char suffix, int pos,
+ boolean always, int zeropad) {
+ if (always || amt > 0) {
+ if ((always && zeropad >= 3) || amt > 99) {
+ int dig = amt/100;
+ formatStr[pos] = (char)(dig + '0');
+ pos++;
+ always = true;
+ amt -= (dig*100);
+ }
+ if ((always && zeropad >= 2) || amt > 9) {
+ int dig = amt/10;
+ formatStr[pos] = (char)(dig + '0');
+ pos++;
+ always = true;
+ amt -= (dig*10);
+ }
+ formatStr[pos] = (char)(amt + '0');
+ pos++;
+ formatStr[pos] = suffix;
+ pos++;
+ }
+ return pos;
+ }
+
+ private static int formatDurationLocked(long duration, int fieldLen) {
+ if (sFormatStr.length < fieldLen) {
+ sFormatStr = new char[fieldLen];
+ }
+
+ char[] formatStr = sFormatStr;
+
+ if (duration == 0) {
+ int pos = 0;
+ fieldLen -= 1;
+ while (pos < fieldLen) {
+ formatStr[pos] = ' ';
+ }
+ formatStr[pos] = '0';
+ return pos+1;
+ }
+
+ char prefix;
if (duration > 0) {
- builder.append("+");
+ prefix = '+';
} else {
- builder.append("-");
+ prefix = '-';
duration = -duration;
}
@@ -166,93 +222,62 @@
seconds -= minutes * SECONDS_PER_MINUTE;
}
- boolean doall = false;
- if (days > 0) {
- builder.append(days);
- builder.append('d');
- doall = true;
+ int pos = 0;
+
+ if (fieldLen != 0) {
+ int myLen = accumField(days, 1, false, 0);
+ myLen += accumField(hours, 1, myLen > 0, 2);
+ myLen += accumField(minutes, 1, myLen > 0, 2);
+ myLen += accumField(seconds, 1, myLen > 0, 2);
+ myLen += accumField(millis, 2, true, myLen > 0 ? 3 : 0) + 1;
+ while (myLen < fieldLen) {
+ formatStr[pos] = ' ';
+ pos++;
+ myLen++;
+ }
}
- if (doall || hours > 0) {
- builder.append(hours);
- builder.append('h');
- doall = true;
+
+ formatStr[pos] = prefix;
+ pos++;
+
+ int start = pos;
+ boolean zeropad = fieldLen != 0;
+ pos = printField(formatStr, days, 'd', pos, false, 0);
+ pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0);
+ pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0);
+ pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0);
+ pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0);
+ formatStr[pos] = 's';
+ return pos + 1;
+ }
+
+ /** @hide Just for debugging; not internationalized. */
+ public static void formatDuration(long duration, StringBuilder builder) {
+ synchronized (sFormatSync) {
+ int len = formatDurationLocked(duration, 0);
+ builder.append(sFormatStr, 0, len);
}
- if (doall || minutes > 0) {
- builder.append(minutes);
- builder.append('m');
- doall = true;
+ }
+
+ /** @hide Just for debugging; not internationalized. */
+ public static void formatDuration(long duration, PrintWriter pw, int fieldLen) {
+ synchronized (sFormatSync) {
+ int len = formatDurationLocked(duration, fieldLen);
+ pw.print(new String(sFormatStr, 0, len));
}
- if (doall || seconds > 0) {
- builder.append(seconds);
- builder.append('s');
- doall = true;
- }
- builder.append(millis);
- builder.append("ms");
}
/** @hide Just for debugging; not internationalized. */
public static void formatDuration(long duration, PrintWriter pw) {
- if (duration == 0) {
- pw.print("0");
- return;
- }
- if (duration > 0) {
- pw.print("+");
- } else {
- pw.print("-");
- duration = -duration;
- }
-
- int millis = (int)(duration%1000);
- int seconds = (int) Math.floor(duration / 1000);
- int days = 0, hours = 0, minutes = 0;
-
- if (seconds > SECONDS_PER_DAY) {
- days = seconds / SECONDS_PER_DAY;
- seconds -= days * SECONDS_PER_DAY;
- }
- if (seconds > SECONDS_PER_HOUR) {
- hours = seconds / SECONDS_PER_HOUR;
- seconds -= hours * SECONDS_PER_HOUR;
- }
- if (seconds > SECONDS_PER_MINUTE) {
- minutes = seconds / SECONDS_PER_MINUTE;
- seconds -= minutes * SECONDS_PER_MINUTE;
- }
-
- boolean doall = false;
- if (days > 0) {
- pw.print(days);
- pw.print('d');
- doall = true;
- }
- if (doall || hours > 0) {
- pw.print(hours);
- pw.print('h');
- doall = true;
- }
- if (doall || minutes > 0) {
- pw.print(minutes);
- pw.print('m');
- doall = true;
- }
- if (doall || seconds > 0) {
- pw.print(seconds);
- pw.print('s');
- doall = true;
- }
- pw.print(millis);
- pw.print("ms");
+ formatDuration(duration, pw, 0);
}
-
-
+
/** @hide Just for debugging; not internationalized. */
public static void formatDuration(long time, long now, PrintWriter pw) {
if (time == 0) {
pw.print("--");
return;
}
- formatDuration(time-now, pw);
+ formatDuration(time-now, pw, 0);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7355353..f8d79e5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7298,9 +7298,6 @@
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
}
- if (Config.DEBUG && ViewDebug.profileDrawing) {
- EventLog.writeEvent(60002, hashCode());
- }
int width = mRight - mLeft;
int height = mBottom - mTop;
@@ -7738,7 +7735,8 @@
saveCount = canvas.getSaveCount();
int solidColor = getSolidColor();
- if (solidColor == 0) {
+ // TODO: Temporarily disable fading edges with hardware acceleration
+ if (solidColor == 0 && !canvas.isHardwareAccelerated()) {
final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
if (drawTop) {
@@ -7946,6 +7944,7 @@
* @param r Right position, relative to parent
* @param b Bottom position, relative to parent
*/
+ @SuppressWarnings({"unchecked"})
public final void layout(int l, int t, int r, int b) {
int oldL = mLeft;
int oldT = mTop;
@@ -10129,11 +10128,6 @@
final RectF mTmpTransformRect = new RectF();
/**
- * Temporary for use in computing invalidation areas with transformed views
- */
- final float[] mTmpTransformBounds = new float[8];
-
- /**
* Temporary list for use in collecting focusable descendents of a view.
*/
final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 22cc3a8..b1d5272 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -119,24 +119,21 @@
*
* @hide
*/
- @Debug.DebugProperty
- public static boolean profileDrawing = false;
+ public static final boolean DEBUG_PROFILE_DRAWING = false;
/**
* Profiles layout times in the events log.
*
* @hide
*/
- @Debug.DebugProperty
- public static boolean profileLayout = false;
+ public static final boolean DEBUG_PROFILE_LAYOUT = false;
/**
* Profiles real fps (times between draws) and displays the result.
*
* @hide
*/
- @Debug.DebugProperty
- public static boolean showFps = false;
+ public static final boolean DEBUG_SHOW_FPS = false;
/**
* <p>Enables or disables views consistency check. Even when this property is enabled,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dee6e73..363ccd6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -32,8 +32,6 @@
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
-import android.util.Config;
-import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
@@ -2020,9 +2018,6 @@
cachePaint.setAlpha(255);
mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
}
- if (Config.DEBUG && ViewDebug.profileDrawing) {
- EventLog.writeEvent(60003, hashCode());
- }
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 5d4ac37..e5fc859 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -946,8 +946,8 @@
mSurfaceHolder.mSurfaceLock.unlock();
}
}
-
- if (hwIntialized) {
+
+ if (hwIntialized || (windowShouldResize && mHwRenderer != null)) {
mHwRenderer.setup(mWidth, mHeight);
}
@@ -1008,7 +1008,7 @@
TAG, "Laying out " + host + " to (" +
host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
long startTime = 0L;
- if (ViewDebug.profileLayout) {
+ if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
startTime = SystemClock.elapsedRealtime();
}
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
@@ -1021,7 +1021,7 @@
}
}
- if (ViewDebug.profileLayout) {
+ if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
}
@@ -1321,7 +1321,7 @@
//canvas.drawARGB(255, 255, 0, 0);
}
- if (ViewDebug.profileDrawing) {
+ if (ViewDebug.DEBUG_PROFILE_DRAWING) {
startTime = SystemClock.elapsedRealtime();
}
@@ -1364,7 +1364,7 @@
mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
}
- if (SHOW_FPS || ViewDebug.showFps) {
+ if (SHOW_FPS || ViewDebug.DEBUG_SHOW_FPS) {
int now = (int)SystemClock.elapsedRealtime();
if (sDrawTime != 0) {
nativeShowFPS(canvas, now - sDrawTime);
@@ -1372,7 +1372,7 @@
sDrawTime = now;
}
- if (ViewDebug.profileDrawing) {
+ if (ViewDebug.DEBUG_PROFILE_DRAWING) {
EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
}
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 0ed5fc5..d81d7f2 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -211,6 +211,7 @@
private boolean mNavDump = false;
private boolean mSupportZoom = true;
private boolean mBuiltInZoomControls = false;
+ private boolean mDisplayZoomControls = true;
private boolean mAllowFileAccess = true;
private boolean mLoadWithOverviewMode = false;
private boolean mEnableSmoothTransition = false;
@@ -508,6 +509,26 @@
}
/**
+ * Sets whether the on screen zoom buttons are used.
+ * A combination of built in zoom controls enabled
+ * and on screen zoom controls disabled allows for pinch to zoom
+ * to work without the on screen controls
+ * @hide
+ */
+ public void setDisplayZoomControls(boolean enabled) {
+ mDisplayZoomControls = enabled;
+ mWebView.updateMultiTouchSupport(mContext);
+ }
+
+ /**
+ * Returns true if the on screen zoom buttons are being used.
+ * @hide
+ */
+ public boolean getDisplayZoomControls() {
+ return mDisplayZoomControls;
+ }
+
+ /**
* Enable or disable file access within WebView. File access is enabled by
* default.
*/
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 33ebcf5..1323217 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -856,7 +856,8 @@
private ZoomControlBase getCurrentZoomControl() {
if (mWebView.getSettings() != null && mWebView.getSettings().supportZoom()) {
if (mWebView.getSettings().getBuiltInZoomControls()) {
- if (mEmbeddedZoomControl == null) {
+ if ((mEmbeddedZoomControl == null)
+ && mWebView.getSettings().getDisplayZoomControls()) {
mEmbeddedZoomControl = new ZoomControlEmbedded(this, mWebView);
}
return mEmbeddedZoomControl;
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 0636d72..830e899 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -31,6 +31,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -128,6 +129,13 @@
boolean mShouldLoop = true;
/**
+ * The width and height of some child, used as a size reference in-case our
+ * dimensions are unspecified by the parent.
+ */
+ int mReferenceChildWidth = -1;
+ int mReferenceChildHeight = -1;
+
+ /**
* TODO: Animation stuff is still in flux, waiting on the new framework to settle a bit.
*/
Animation mInAnimation;
@@ -414,7 +422,7 @@
FrameLayout fl = new FrameLayout(mContext);
fl.addView(newView);
mActiveViews[index] = fl;
- addViewInLayout(fl, -1, createOrReuseLayoutParams(fl));
+ addChild(fl);
applyTransformForChildAtIndex(fl, newRelativeIndex);
animateViewForTransition(-1, newRelativeIndex, fl);
}
@@ -451,6 +459,64 @@
}
}
+ private void addChild(View child) {
+ addViewInLayout(child, -1, createOrReuseLayoutParams(child));
+
+ // This code is used to obtain a reference width and height of a child in case we need
+ // to decide our own size. TODO: Do we want to update the size of the child that we're
+ // using for reference size? If so, when?
+ if (mReferenceChildWidth == -1 || mReferenceChildHeight == -1) {
+ int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ child.measure(measureSpec, measureSpec);
+ mReferenceChildWidth = child.getMeasuredWidth();
+ mReferenceChildHeight = child.getMeasuredHeight();
+ }
+ }
+
+ private void measureChildren() {
+ final int count = getChildCount();
+ final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
+ final int childHeight = mMeasuredHeight - mPaddingTop - mPaddingBottom;
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1);
+
+ // We need to deal with the case where our parent hasn't told us how
+ // big we should be. In this case we try to use the desired size of the first
+ // child added.
+ if (heightSpecMode == MeasureSpec.UNSPECIFIED) {
+ heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop +
+ mPaddingBottom : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ heightSpecSize = haveChildRefSize ? Math.min(mReferenceChildHeight + mPaddingTop +
+ mPaddingBottom, heightSpecSize) : 0;
+ }
+
+ if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
+ widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight, widthSpecSize) : 0;
+ }
+
+ setMeasuredDimension(widthSpecSize, heightSpecSize);
+ measureChildren();
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
boolean dataChanged = mDataChanged;
@@ -472,8 +538,7 @@
int childRight = mPaddingLeft + child.getMeasuredWidth();
int childBottom = mPaddingTop + child.getMeasuredHeight();
- child.layout(mPaddingLeft, mPaddingTop,
- childRight, childBottom);
+ child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom);
}
mDataChanged = false;
}
@@ -538,31 +603,6 @@
setDisplayedChild(mWhichChild);
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int count = getChildCount();
-
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
-
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- lp.width = widthSpecSize - mPaddingLeft - mPaddingRight;
- lp.height = heightSpecSize - mPaddingTop - mPaddingBottom;
-
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
- MeasureSpec.EXACTLY);
- int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
- MeasureSpec.EXACTLY);
-
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
- }
- setMeasuredDimension(widthSpecSize, heightSpecSize);
- }
-
/**
* Shows only the specified child. The other displays Views exit the screen
* with the {@link #getOutAnimation() out animation} and the specified child
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 50fbb6b..5598c65 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -247,6 +247,7 @@
trigger = true;
createUri = Uri.fromParts("tel", (String)cookie, null);
+ //$FALL-THROUGH$
case TOKEN_PHONE_LOOKUP: {
if (cursor != null && cursor.moveToFirst()) {
long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
@@ -260,12 +261,14 @@
trigger = true;
createUri = Uri.fromParts("mailto", (String)cookie, null);
+ //$FALL-THROUGH$
case TOKEN_EMAIL_LOOKUP: {
if (cursor != null && cursor.moveToFirst()) {
long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
lookupUri = Contacts.getLookupUri(contactId, lookupKey);
}
+ break;
}
case TOKEN_CONTACT_LOOKUP_AND_TRIGGER: {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 9816b39..9025b83 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -16,11 +16,11 @@
package android.widget;
-import java.util.WeakHashMap;
-
import android.animation.PropertyAnimator;
+import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -28,6 +28,7 @@
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.TableMaskFilter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -35,6 +36,8 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.LinearInterpolator;
import android.widget.RemoteViews.RemoteView;
@@ -53,6 +56,19 @@
private final int MINIMUM_ANIMATION_DURATION = 50;
/**
+ * Parameters effecting the perspective visuals
+ */
+ private static float PERSPECTIVE_SHIFT_FACTOR = 0.12f;
+ private static float PERSPECTIVE_SCALE_FACTOR = 0.35f;
+
+ /**
+ * Represent the two possible stack modes, one where items slide up, and the other
+ * where items slide down. The perspective is also inverted between these two modes.
+ */
+ private static final int ITEMS_SLIDE_UP = 0;
+ private static final int ITEMS_SLIDE_DOWN = 1;
+
+ /**
* These specify the different gesture states
*/
private static final int GESTURE_NONE = 0;
@@ -66,8 +82,6 @@
private static final float SWIPE_THRESHOLD_RATIO = 0.35f;
private static final float SLIDE_UP_RATIO = 0.7f;
- private final WeakHashMap<View, Float> mRotations = new WeakHashMap<View, Float>();
-
/**
* Sentinel value for no current active pointer.
* Used by {@link #mActivePointerId}.
@@ -75,6 +89,12 @@
private static final int INVALID_POINTER = -1;
/**
+ * Number of active views in the stack. One fewer view is actually visible, as one is hidden.
+ */
+ private static final int NUM_ACTIVE_VIEWS = 5;
+
+
+ /**
* These variables are all related to the current state of touch interaction
* with the stack
*/
@@ -95,6 +115,7 @@
private boolean mFirstLayoutHappened = false;
private ViewGroup mAncestorContainingAllChildren = null;
private int mAncestorHeight = 0;
+ private int mStackMode;
public StackView(Context context) {
super(context);
@@ -107,7 +128,7 @@
}
private void initStackView() {
- configureViewAnimator(4, 2, false);
+ configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2, false);
setStaticTransformationsEnabled(true);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
@@ -125,6 +146,11 @@
setClipChildren(false);
setClipToPadding(false);
+ // This sets the form of the StackView, which is currently to have the perspective-shifted
+ // views above the active view, and have items slide down when sliding out. The opposite is
+ // available by using ITEMS_SLIDE_UP.
+ mStackMode = ITEMS_SLIDE_DOWN;
+
// This is a flag to indicate the the stack is loading for the first time
mWhichChild = -1;
}
@@ -140,7 +166,7 @@
}
view.setVisibility(VISIBLE);
- PropertyAnimator fadeIn = new PropertyAnimator(DEFAULT_ANIMATION_DURATION,
+ PropertyAnimator<Float> fadeIn = new PropertyAnimator<Float>(DEFAULT_ANIMATION_DURATION,
view, "alpha", view.getAlpha(), 1.0f);
fadeIn.start();
} else if (fromIndex == mNumActiveViews - 1 && toIndex == mNumActiveViews - 2) {
@@ -148,49 +174,32 @@
view.setVisibility(VISIBLE);
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- int largestDuration =
- Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
-
- int duration = largestDuration;
- if (mYVelocity != 0) {
- duration = 1000*(0 - lp.verticalOffset)/Math.abs(mYVelocity);
- }
-
- duration = Math.min(duration, largestDuration);
- duration = Math.max(duration, MINIMUM_ANIMATION_DURATION);
+ int duration = Math.round(mStackSlider.getDurationForNeutralPosition(mYVelocity));
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator slideInY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 0);
- slideInY.setInterpolator(new LinearInterpolator());
- slideInY.start();
- PropertyAnimator slideInX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- slideInX.setInterpolator(new LinearInterpolator());
- slideInX.start();
+ PropertyValuesHolder<Float> slideInY =
+ new PropertyValuesHolder<Float>("YProgress", 0.0f);
+ PropertyValuesHolder<Float> slideInX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ slideInX, slideInY);
+ pa.setInterpolator(new LinearInterpolator());
+ pa.start();
} else if (fromIndex == mNumActiveViews - 2 && toIndex == mNumActiveViews - 1) {
// Slide item out
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- int largestDuration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
- DEFAULT_ANIMATION_DURATION);
- int duration = largestDuration;
- if (mYVelocity != 0) {
- duration = 1000*(lp.verticalOffset + mViewHeight)/Math.abs(mYVelocity);
- }
-
- duration = Math.min(duration, largestDuration);
- duration = Math.max(duration, MINIMUM_ANIMATION_DURATION);
+ int duration = Math.round(mStackSlider.getDurationForOffscreenPosition(mYVelocity));
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator slideOutY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 1);
- slideOutY.setInterpolator(new LinearInterpolator());
- slideOutY.start();
- PropertyAnimator slideOutX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- slideOutX.setInterpolator(new LinearInterpolator());
- slideOutX.start();
+ PropertyValuesHolder<Float> slideOutY =
+ new PropertyValuesHolder<Float>("YProgress", 1.0f);
+ PropertyValuesHolder<Float> slideOutX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ slideOutX, slideOutY);
+ pa.setInterpolator(new LinearInterpolator());
+ pa.start();
} else if (fromIndex == -1 && toIndex == mNumActiveViews - 1) {
// Make sure this view that is "waiting in the wings" is invisible
view.setAlpha(0.0f);
@@ -199,28 +208,41 @@
lp.setVerticalOffset(-mViewHeight);
} else if (toIndex == -1) {
// Fade item out
- PropertyAnimator fadeOut = new PropertyAnimator(DEFAULT_ANIMATION_DURATION,
- view, "alpha", view.getAlpha(), 0);
+ PropertyAnimator<Float> fadeOut = new PropertyAnimator<Float>
+ (DEFAULT_ANIMATION_DURATION, view, "alpha", view.getAlpha(), 0.0f);
fadeOut.start();
}
+
+ // Implement the faked perspective
+ if (toIndex != -1) {
+ float maxPerpectiveShift = mViewHeight * PERSPECTIVE_SHIFT_FACTOR;
+ int index = toIndex;
+
+ if (toIndex == mNumActiveViews -1) index--;
+
+ float r = (index * 1.0f) / (mNumActiveViews - 2);
+
+ float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r);
+ PropertyValuesHolder<Float> scaleX = new PropertyValuesHolder<Float>("scaleX", scale);
+ PropertyValuesHolder<Float> scaleY = new PropertyValuesHolder<Float>("scaleY", scale);
+
+ r = (float) Math.pow(r, 2);
+
+ int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
+ float transY = -stackDirection * r * maxPerpectiveShift +
+ stackDirection * (1 - scale) * (mViewHeight / 2.0f);
+
+ PropertyValuesHolder<Float> translationY =
+ new PropertyValuesHolder<Float>("translationY", transY);
+ PropertyAnimator pa = new PropertyAnimator(100, view, scaleX, scaleY, translationY);
+ pa.start();
+ }
}
/**
* Apply any necessary tranforms for the child that is being added.
*/
void applyTransformForChildAtIndex(View child, int relativeIndex) {
- if (!mRotations.containsKey(child)) {
- float rotation = (float) (Math.random()*26 - 13);
- mRotations.put(child, rotation);
- child.setRotation(rotation);
- }
-
- // Child has been removed
- if (relativeIndex == -1) {
- if (mRotations.containsKey(child)) {
- mRotations.remove(child);
- }
- }
}
@Override
@@ -248,8 +270,8 @@
private void onLayout() {
if (!mFirstLayoutHappened) {
- mViewHeight = Math.round(SLIDE_UP_RATIO*getMeasuredHeight());
- mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO*mViewHeight);
+ mViewHeight = Math.round(SLIDE_UP_RATIO * getMeasuredHeight());
+ mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO * mViewHeight);
mFirstLayoutHappened = true;
}
}
@@ -299,8 +321,14 @@
cancelLongPress();
requestDisallowInterceptTouchEvent(true);
- int activeIndex = swipeGestureType == GESTURE_SLIDE_DOWN ? mNumActiveViews - 1
- : mNumActiveViews - 2;
+ int activeIndex;
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ?
+ mNumActiveViews - 1 : mNumActiveViews - 2;
+ } else {
+ activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ?
+ mNumActiveViews - 2 : mNumActiveViews - 1;
+ }
if (mAdapter == null) return;
@@ -317,6 +345,8 @@
if (v == null) return;
mHighlight.setImageBitmap(sHolographicHelper.createOutline(v));
+ mHighlight.setRotation(v.getRotation());
+ mHighlight.setTranslationY(v.getTranslationY());
mHighlight.bringToFront();
v.bringToFront();
mStackSlider.setView(v);
@@ -352,14 +382,16 @@
case MotionEvent.ACTION_MOVE: {
beginGestureIfNeeded(deltaY);
- float rx = deltaX/(mViewHeight*1.0f);
+ float rx = deltaX / (mViewHeight * 1.0f);
if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
- float r = (deltaY-mTouchSlop*1.0f)/mViewHeight*1.0f;
+ float r = (deltaY - mTouchSlop * 1.0f) / mViewHeight * 1.0f;
+ if (mStackMode == ITEMS_SLIDE_DOWN) r = 1 - r;
mStackSlider.setYProgress(1 - r);
mStackSlider.setXProgress(rx);
return true;
} else if (mSwipeGestureType == GESTURE_SLIDE_UP) {
- float r = -(deltaY + mTouchSlop*1.0f)/mViewHeight*1.0f;
+ float r = -(deltaY + mTouchSlop * 1.0f) / mViewHeight * 1.0f;
+ if (mStackMode == ITEMS_SLIDE_DOWN) r = 1 - r;
mStackSlider.setYProgress(r);
mStackSlider.setXProgress(rx);
return true;
@@ -447,41 +479,59 @@
if (deltaY > mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_DOWN
&& mStackSlider.mMode == StackSlider.NORMAL_MODE) {
// Swipe threshold exceeded, swipe down
- showNext();
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ showNext();
+ } else {
+ showPrevious();
+ }
mHighlight.bringToFront();
} else if (deltaY < -mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_UP
&& mStackSlider.mMode == StackSlider.NORMAL_MODE) {
// Swipe threshold exceeded, swipe up
- showPrevious();
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ showPrevious();
+ } else {
+ showNext();
+ }
+
mHighlight.bringToFront();
- } else if (mSwipeGestureType == GESTURE_SLIDE_UP) {
+ } else if (mSwipeGestureType == GESTURE_SLIDE_UP ) {
// Didn't swipe up far enough, snap back down
- int duration =
- Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
+ int duration;
+ float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 1 : 0;
+ if (mStackMode == ITEMS_SLIDE_UP || mStackSlider.mMode != StackSlider.NORMAL_MODE) {
+ duration = Math.round(mStackSlider.getDurationForNeutralPosition());
+ } else {
+ duration = Math.round(mStackSlider.getDurationForOffscreenPosition());
+ }
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 0);
- snapBackY.setInterpolator(new LinearInterpolator());
- snapBackY.start();
- PropertyAnimator snapBackX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- snapBackX.setInterpolator(new LinearInterpolator());
- snapBackX.start();
+ PropertyValuesHolder<Float> snapBackY =
+ new PropertyValuesHolder<Float>("YProgress", finalYProgress);
+ PropertyValuesHolder<Float> snapBackX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ snapBackX, snapBackY);
+ pa.setInterpolator(new LinearInterpolator());
+ pa.start();
} else if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
// Didn't swipe down far enough, snap back up
- int duration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
- DEFAULT_ANIMATION_DURATION);
+ float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 0 : 1;
+ int duration;
+ if (mStackMode == ITEMS_SLIDE_DOWN || mStackSlider.mMode != StackSlider.NORMAL_MODE) {
+ duration = Math.round(mStackSlider.getDurationForNeutralPosition());
+ } else {
+ duration = Math.round(mStackSlider.getDurationForOffscreenPosition());
+ }
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 1);
- snapBackY.setInterpolator(new LinearInterpolator());
- snapBackY.start();
- PropertyAnimator snapBackX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- snapBackX.setInterpolator(new LinearInterpolator());
- snapBackX.start();
+ PropertyValuesHolder<Float> snapBackY =
+ new PropertyValuesHolder<Float>("YProgress", finalYProgress);
+ PropertyValuesHolder<Float> snapBackX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ snapBackX, snapBackY);
+ pa.start();
}
mActivePointerId = INVALID_POINTER;
@@ -510,22 +560,22 @@
}
private float cubic(float r) {
- return (float) (Math.pow(2*r-1, 3) + 1)/2.0f;
+ return (float) (Math.pow(2 * r - 1, 3) + 1) / 2.0f;
}
private float highlightAlphaInterpolator(float r) {
float pivot = 0.4f;
if (r < pivot) {
- return 0.85f*cubic(r/pivot);
+ return 0.85f * cubic(r / pivot);
} else {
- return 0.85f*cubic(1 - (r-pivot)/(1-pivot));
+ return 0.85f * cubic(1 - (r - pivot) / (1 - pivot));
}
}
private float viewAlphaInterpolator(float r) {
float pivot = 0.3f;
if (r > pivot) {
- return (r - pivot)/(1 - pivot);
+ return (r - pivot) / (1 - pivot);
} else {
return 0;
}
@@ -536,7 +586,7 @@
if (r < pivot) {
return 0;
} else {
- return (r-pivot)/(1-pivot);
+ return (r - pivot) / (1 - pivot);
}
}
@@ -553,13 +603,15 @@
final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
+ int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
+
switch (mMode) {
case NORMAL_MODE:
- viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
- highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ viewLp.setVerticalOffset(Math.round(-r * stackDirection * mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(-r * stackDirection * mViewHeight));
mHighlight.setAlpha(highlightAlphaInterpolator(r));
- float alpha = viewAlphaInterpolator(1-r);
+ float alpha = viewAlphaInterpolator(1 - r);
// We make sure that views which can't be seen (have 0 alpha) are also invisible
// so that they don't interfere with click events.
@@ -571,19 +623,19 @@
}
mView.setAlpha(alpha);
- mView.setRotationX(90.0f*rotationInterpolator(r));
- mHighlight.setRotationX(90.0f*rotationInterpolator(r));
+ mView.setRotationX(stackDirection * 90.0f * rotationInterpolator(r));
+ mHighlight.setRotationX(stackDirection * 90.0f * rotationInterpolator(r));
break;
case BEGINNING_OF_STACK_MODE:
- r = r*0.2f;
- viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
- highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ r = r * 0.2f;
+ viewLp.setVerticalOffset(Math.round(-stackDirection * r * mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(-stackDirection * r * mViewHeight));
mHighlight.setAlpha(highlightAlphaInterpolator(r));
break;
case END_OF_STACK_MODE:
- r = (1-r)*0.2f;
- viewLp.setVerticalOffset(Math.round(r*mViewHeight));
- highlightLp.setVerticalOffset(Math.round(r*mViewHeight));
+ r = (1-r) * 0.2f;
+ viewLp.setVerticalOffset(Math.round(stackDirection * r * mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(stackDirection * r * mViewHeight));
mHighlight.setAlpha(highlightAlphaInterpolator(r));
break;
}
@@ -600,8 +652,8 @@
final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
r *= 0.2f;
- viewLp.setHorizontalOffset(Math.round(r*mViewHeight));
- highlightLp.setHorizontalOffset(Math.round(r*mViewHeight));
+ viewLp.setHorizontalOffset(Math.round(r * mViewHeight));
+ highlightLp.setHorizontalOffset(Math.round(r * mViewHeight));
}
void setMode(int mode) {
@@ -609,31 +661,51 @@
}
float getDurationForNeutralPosition() {
- return getDuration(false);
+ return getDuration(false, 0);
}
float getDurationForOffscreenPosition() {
- return getDuration(mMode == END_OF_STACK_MODE ? false : true);
+ return getDuration(true, 0);
}
- private float getDuration(boolean invert) {
+ float getDurationForNeutralPosition(float velocity) {
+ return getDuration(false, velocity);
+ }
+
+ float getDurationForOffscreenPosition(float velocity) {
+ return getDuration(true, velocity);
+ }
+
+ private float getDuration(boolean invert, float velocity) {
if (mView != null) {
final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
- float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset,2) +
- Math.pow(viewLp.verticalOffset,2));
+ float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset, 2) +
+ Math.pow(viewLp.verticalOffset, 2));
float maxd = (float) Math.sqrt(Math.pow(mViewHeight, 2) +
- Math.pow(0.4f*mViewHeight, 2));
- return invert ? (1-d/maxd) : d/maxd;
+ Math.pow(0.4f * mViewHeight, 2));
+
+ if (velocity == 0) {
+ return (invert ? (1 - d / maxd) : d / maxd) * DEFAULT_ANIMATION_DURATION;
+ } else {
+ float duration = invert ? d / Math.abs(velocity) :
+ (maxd - d) / Math.abs(velocity);
+ if (duration < MINIMUM_ANIMATION_DURATION ||
+ duration > DEFAULT_ANIMATION_DURATION) {
+ return getDuration(invert, 0);
+ } else {
+ return duration;
+ }
+ }
}
return 0;
}
- float getYProgress() {
+ public float getYProgress() {
return mYProgress;
}
- float getXProgress() {
+ public float getXProgress() {
return mXProgress;
}
}
@@ -654,6 +726,8 @@
LayoutParams lp = (LayoutParams) currentLp;
lp.setHorizontalOffset(0);
lp.setVerticalOffset(0);
+ lp.width = 0;
+ lp.width = 0;
return lp;
}
return new LayoutParams(v);
@@ -684,15 +758,59 @@
child.layout(mPaddingLeft + lp.horizontalOffset, mPaddingTop + lp.verticalOffset,
childRight + lp.horizontalOffset, childBottom + lp.verticalOffset);
- //TODO: temp until fix in View
- child.setPivotX(child.getMeasuredWidth()/2);
- child.setPivotY(child.getMeasuredHeight()/2);
}
mDataChanged = false;
onLayout();
}
+ private void measureChildren() {
+ final int count = getChildCount();
+ final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
+ final int childHeight = Math.round(mMeasuredHeight*(1-PERSPECTIVE_SHIFT_FACTOR))
+ - mPaddingTop - mPaddingBottom;
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1);
+
+ // We need to deal with the case where our parent hasn't told us how
+ // big we should be. In this case we should
+ float factor = 1/(1 - PERSPECTIVE_SHIFT_FACTOR);
+ if (heightSpecMode == MeasureSpec.UNSPECIFIED) {
+ heightSpecSize = haveChildRefSize ?
+ Math.round(mReferenceChildHeight * (1 + factor)) +
+ mPaddingTop + mPaddingBottom : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ heightSpecSize = haveChildRefSize ? Math.min(
+ Math.round(mReferenceChildHeight * (1 + factor)) + mPaddingTop +
+ mPaddingBottom, heightSpecSize) : 0;
+ }
+
+ if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
+ widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight, widthSpecSize) : 0;
+ }
+
+ setMeasuredDimension(widthSpecSize, heightSpecSize);
+ measureChildren();
+ }
+
class LayoutParams extends ViewGroup.LayoutParams {
int horizontalOffset;
int verticalOffset;
@@ -700,6 +818,8 @@
LayoutParams(View view) {
super(0, 0);
+ width = 0;
+ height = 0;
horizontalOffset = 0;
verticalOffset = 0;
mView = view;
@@ -709,6 +829,8 @@
super(c, attrs);
horizontalOffset = 0;
verticalOffset = 0;
+ width = 0;
+ height = 0;
}
private Rect parentRect = new Rect();
@@ -731,6 +853,10 @@
gp = (View) p.getParent();
parentRect.set(p.getLeft() - gp.getScrollX(), p.getTop() - gp.getScrollY(),
p.getRight() - gp.getScrollX(), p.getBottom() - gp.getScrollY());
+
+ // TODO: we need to stop early here if we've hit the edge of the screen
+ // so as to prevent us from walking too high in the hierarchy. A lot of this
+ // code might become a lot more straightforward.
}
if (depth > mAncestorHeight) {
@@ -799,7 +925,7 @@
private static class HolographicHelper {
private final Paint mHolographicPaint = new Paint();
private final Paint mErasePaint = new Paint();
- private final float STROKE_WIDTH = 3.0f;
+ private final Paint mBlurPaint = new Paint();
HolographicHelper() {
initializePaints();
@@ -808,8 +934,10 @@
void initializePaints() {
mHolographicPaint.setColor(0xff6699ff);
mHolographicPaint.setFilterBitmap(true);
+ mHolographicPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mErasePaint.setFilterBitmap(true);
+ mBlurPaint.setMaskFilter(new BlurMaskFilter(2, BlurMaskFilter.Blur.NORMAL));
}
Bitmap createOutline(View v) {
@@ -822,31 +950,31 @@
Canvas canvas = new Canvas(bitmap);
float rotationX = v.getRotationX();
+ float rotation = v.getRotation();
+ float translationY = v.getTranslationY();
v.setRotationX(0);
+ v.setRotation(0);
+ v.setTranslationY(0);
canvas.concat(v.getMatrix());
v.draw(canvas);
-
v.setRotationX(rotationX);
+ v.setRotation(rotation);
+ v.setTranslationY(translationY);
+ canvas.setMatrix(id);
drawOutline(canvas, bitmap);
return bitmap;
}
final Matrix id = new Matrix();
- final Matrix scaleMatrix = new Matrix();
void drawOutline(Canvas dest, Bitmap src) {
- Bitmap mask = src.extractAlpha();
-
+ int[] xy = new int[2];
+ Bitmap mask = src.extractAlpha(mBlurPaint, xy);
+ Canvas maskCanvas = new Canvas(mask);
+ maskCanvas.drawBitmap(src, -xy[0], -xy[1], mErasePaint);
dest.drawColor(0, PorterDuff.Mode.CLEAR);
-
- float xScale = STROKE_WIDTH*2/(dest.getWidth());
- float yScale = STROKE_WIDTH*2/(dest.getHeight());
-
- scaleMatrix.reset();
- scaleMatrix.preScale(1+xScale, 1+yScale, dest.getWidth()/2, dest.getHeight()/2);
dest.setMatrix(id);
- dest.drawBitmap(mask, scaleMatrix, mHolographicPaint);
- dest.drawBitmap(mask, id, mErasePaint);
+ dest.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
mask.recycle();
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0a1c8ff..a6a031a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3345,11 +3345,6 @@
}
}
- public class Pid {
- long mWakeSum;
- long mWakeStart;
- }
-
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
@@ -3364,6 +3359,10 @@
return ps;
}
+ public SparseArray<? extends Pid> getPidStats() {
+ return mPids;
+ }
+
public Pid getPidStatsLocked(int pid) {
Pid p = mPids.get(pid);
if (p == null) {
@@ -3588,6 +3587,11 @@
}
@Override
+ public long getHistoryBaseTime() {
+ return mHistoryBaseTime;
+ }
+
+ @Override
public int getStartCount() {
return mStartCount;
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index cb0bdd3..65040fc 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -106,12 +106,13 @@
android_graphics_PixelFormat.cpp \
android/graphics/Picture.cpp \
android/graphics/PorterDuff.cpp \
- android/graphics/LargeBitmap.cpp \
+ android/graphics/BitmapRegionDecoder.cpp \
android/graphics/Rasterizer.cpp \
android/graphics/Region.cpp \
android/graphics/Shader.cpp \
android/graphics/TextLayout.cpp \
android/graphics/Typeface.cpp \
+ android/graphics/Utils.cpp \
android/graphics/Xfermode.cpp \
android/graphics/YuvToJpegEncoder.cpp \
android_media_AudioRecord.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c9d7e7f..43e59f9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -53,7 +53,7 @@
extern int register_android_os_Process(JNIEnv* env);
extern int register_android_graphics_Bitmap(JNIEnv*);
extern int register_android_graphics_BitmapFactory(JNIEnv*);
-extern int register_android_graphics_LargeBitmap(JNIEnv*);
+extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
extern int register_android_graphics_Camera(JNIEnv* env);
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_Interpolator(JNIEnv* env);
@@ -1245,7 +1245,7 @@
REG_JNI(register_android_graphics_Bitmap),
REG_JNI(register_android_graphics_BitmapFactory),
- REG_JNI(register_android_graphics_LargeBitmap),
+ REG_JNI(register_android_graphics_BitmapRegionDecoder),
REG_JNI(register_android_graphics_Camera),
REG_JNI(register_android_graphics_Canvas),
REG_JNI(register_android_graphics_ColorFilter),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 254d9a4..48539dc 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -10,6 +10,7 @@
#include "SkUtils.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include "AutoDecodeCancel.h"
+#include "Utils.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/Asset.h>
@@ -98,57 +99,6 @@
}
};
-class AssetStreamAdaptor : public SkStream {
-public:
- AssetStreamAdaptor(Asset* a) : fAsset(a) {}
-
- virtual bool rewind() {
- off_t pos = fAsset->seek(0, SEEK_SET);
- if (pos == (off_t)-1) {
- SkDebugf("----- fAsset->seek(rewind) failed\n");
- return false;
- }
- return true;
- }
-
- virtual size_t read(void* buffer, size_t size) {
- ssize_t amount;
-
- if (NULL == buffer) {
- if (0 == size) { // caller is asking us for our total length
- return fAsset->getLength();
- }
- // asset->seek returns new total offset
- // we want to return amount that was skipped
-
- off_t oldOffset = fAsset->seek(0, SEEK_CUR);
- if (-1 == oldOffset) {
- SkDebugf("---- fAsset->seek(oldOffset) failed\n");
- return 0;
- }
- off_t newOffset = fAsset->seek(size, SEEK_CUR);
- if (-1 == newOffset) {
- SkDebugf("---- fAsset->seek(%d) failed\n", size);
- return 0;
- }
- amount = newOffset - oldOffset;
- } else {
- amount = fAsset->read(buffer, size);
- if (amount <= 0) {
- SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount);
- }
- }
-
- if (amount < 0) {
- amount = 0;
- }
- return amount;
- }
-
-private:
- Asset* fAsset;
-};
-
///////////////////////////////////////////////////////////////////////////////
static inline int32_t validOrNeg1(bool isValid, int32_t value) {
@@ -200,12 +150,6 @@
!env->GetBooleanField(options, gOptions_nativeAllocFieldID);
}
-static jobject nullObjectReturn(const char msg[]) {
- if (msg) {
- SkDebugf("--- %s\n", msg);
- }
- return NULL;
-}
static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
int sampleSize, bool ditherImage) {
@@ -376,23 +320,6 @@
return size;
}
-/** Restore the file descriptor's offset in our destructor
- */
-class AutoFDSeek {
-public:
- AutoFDSeek(int fd) : fFD(fd) {
- fCurr = ::lseek(fd, 0, SEEK_CUR);
- }
- ~AutoFDSeek() {
- if (fCurr >= 0) {
- ::lseek(fFD, fCurr, SEEK_SET);
- }
- }
-private:
- int fFD;
- off_t fCurr;
-};
-
static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz,
jobject fileDescriptor,
jobject padding,
@@ -559,107 +486,6 @@
}
}
-static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream, bool isShareable) {
- SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
- int width, height;
- if (NULL == decoder) {
- doThrowIOE(env, "Image format not supported");
- return nullObjectReturn("SkImageDecoder::Factory returned null");
- }
-
- JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
- decoder->setAllocator(javaAllocator);
- JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
- decoder->setReporter(javaMemoryReporter);
- javaAllocator->unref();
- javaMemoryReporter->unref();
-
- if (!decoder->buildTileIndex(stream, &width, &height, isShareable)) {
- char msg[1024];
- snprintf(msg, 1023, "Image failed to decode using %s decoder", decoder->getFormatName());
- doThrowIOE(env, msg);
- return nullObjectReturn("decoder->buildTileIndex returned false");
- }
-
- SkLargeBitmap *bm = new SkLargeBitmap(decoder, width, height);
-
- return GraphicsJNI::createLargeBitmap(env, bm);
-}
-
-static jobject nativeCreateLargeBitmapFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
- int offset, int length, jboolean isShareable) {
- AutoJavaByteArray ar(env, byteArray);
- SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, false);
- SkAutoUnref aur(stream);
- if (isShareable) {
- aur.detach();
- }
- return doBuildTileIndex(env, stream, isShareable);
-}
-
-static jobject nativeCreateLargeBitmapFromFileDescriptor(JNIEnv* env, jobject clazz,
- jobject fileDescriptor, jboolean isShareable) {
- NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
-
- jint descriptor = env->GetIntField(fileDescriptor,
- gFileDescriptor_descriptor);
- bool weOwnTheFD = false;
-
- if (isShareable) {
- int newFD = ::dup(descriptor);
- if (-1 != newFD) {
- weOwnTheFD = true;
- descriptor = newFD;
- }
- }
-
- SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
- SkAutoUnref aur(stream);
- if (!stream->isValid()) {
- return NULL;
- }
-
- if (isShareable) {
- aur.detach();
- }
-
- /* Restore our offset when we leave, so we can be called more than once
- with the same descriptor. This is only required if we didn't dup the
- file descriptor, but it is OK to do it all the time.
- */
- AutoFDSeek as(descriptor);
-
- return doBuildTileIndex(env, stream, isShareable);
-}
-
-static jobject nativeCreateLargeBitmapFromStream(JNIEnv* env, jobject clazz,
- jobject is, // InputStream
- jbyteArray storage, // byte[]
- jboolean isShareable) {
- jobject largeBitmap = NULL;
- SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
-
- if (stream) {
- // for now we don't allow shareable with java inputstreams
- largeBitmap = doBuildTileIndex(env, stream, false);
- stream->unref();
- }
- return largeBitmap;
-}
-
-static jobject nativeCreateLargeBitmapFromAsset(JNIEnv* env, jobject clazz,
- jint native_asset, // Asset
- jboolean isShareable) {
- SkStream* stream;
- Asset* asset = reinterpret_cast<Asset*>(native_asset);
- stream = new AssetStreamAdaptor(asset);
- SkAutoUnref aur(stream);
- if (isShareable) {
- aur.detach();
- }
- return doBuildTileIndex(env, stream, isShareable);
-}
-
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gMethods[] = {
@@ -689,26 +515,6 @@
},
{ "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig },
-
- { "nativeCreateLargeBitmap",
- "([BIIZ)Landroid/graphics/LargeBitmap;",
- (void*)nativeCreateLargeBitmapFromByteArray
- },
-
- { "nativeCreateLargeBitmap",
- "(Ljava/io/InputStream;[BZ)Landroid/graphics/LargeBitmap;",
- (void*)nativeCreateLargeBitmapFromStream
- },
-
- { "nativeCreateLargeBitmap",
- "(Ljava/io/FileDescriptor;Z)Landroid/graphics/LargeBitmap;",
- (void*)nativeCreateLargeBitmapFromFileDescriptor
- },
-
- { "nativeCreateLargeBitmap",
- "(IZ)Landroid/graphics/LargeBitmap;",
- (void*)nativeCreateLargeBitmapFromAsset
- },
};
static JNINativeMethod gOptionsMethods[] = {
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
new file mode 100644
index 0000000..6a5be44
--- /dev/null
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BitmapRegionDecoder"
+
+#include "SkBitmap.h"
+#include "SkImageEncoder.h"
+#include "GraphicsJNI.h"
+#include "SkUtils.h"
+#include "SkTemplates.h"
+#include "SkPixelRef.h"
+#include "SkStream.h"
+#include "BitmapFactory.h"
+#include "AutoDecodeCancel.h"
+#include "SkBitmapRegionDecoder.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+#include "Utils.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include "android_util_Binder.h"
+#include "android_nio_utils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <binder/Parcel.h>
+#include <jni.h>
+#include <utils/Asset.h>
+
+static jclass gFileDescriptor_class;
+static jfieldID gFileDescriptor_descriptor;
+
+#if 0
+ #define TRACE_BITMAP(code) code
+#else
+ #define TRACE_BITMAP(code)
+#endif
+
+using namespace android;
+
+static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream, bool isShareable) {
+ SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
+ int width, height;
+ if (NULL == decoder) {
+ doThrowIOE(env, "Image format not supported");
+ return nullObjectReturn("SkImageDecoder::Factory returned null");
+ }
+
+ JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
+ decoder->setAllocator(javaAllocator);
+ JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
+ decoder->setReporter(javaMemoryReporter);
+ javaAllocator->unref();
+ javaMemoryReporter->unref();
+
+ if (!decoder->buildTileIndex(stream, &width, &height, isShareable)) {
+ char msg[1024];
+ snprintf(msg, 1023, "Image failed to decode using %s decoder", decoder->getFormatName());
+ doThrowIOE(env, msg);
+ return nullObjectReturn("decoder->buildTileIndex returned false");
+ }
+
+ SkBitmapRegionDecoder *brd = new SkBitmapRegionDecoder(decoder, width, height);
+
+ return GraphicsJNI::createBitmapRegionDecoder(env, brd);
+}
+
+static jobject nativeNewInstanceFromByteArray(JNIEnv* env,
+ jobject, jbyteArray byteArray, int offset, int length,
+ jboolean isShareable) {
+ AutoJavaByteArray ar(env, byteArray);
+ SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, false);
+ SkAutoUnref aur(stream);
+ if (isShareable) {
+ aur.detach();
+ }
+ return doBuildTileIndex(env, stream, isShareable);
+}
+
+static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env,
+ jobject clazz, jobject fileDescriptor, jboolean isShareable) {
+ NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
+
+ jint descriptor = env->GetIntField(fileDescriptor,
+ gFileDescriptor_descriptor);
+ bool weOwnTheFD = false;
+
+ if (isShareable) {
+ int newFD = ::dup(descriptor);
+ if (-1 != newFD) {
+ weOwnTheFD = true;
+ descriptor = newFD;
+ }
+ }
+
+ SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
+ SkAutoUnref aur(stream);
+ if (!stream->isValid()) {
+ return NULL;
+ }
+
+ if (isShareable) {
+ aur.detach();
+ }
+
+ // Restore our offset when we leave, so we can be called more than once
+ // with the same descriptor. This is only required if we didn't dup the
+ // file descriptor, but it is OK to do it all the time.
+ AutoFDSeek as(descriptor);
+
+ return doBuildTileIndex(env, stream, isShareable);
+}
+
+static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
+ jobject is, // InputStream
+ jbyteArray storage, // byte[]
+ jboolean isShareable) {
+ jobject BitmapRegionDecoder = NULL;
+ SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
+
+ if (stream) {
+ // for now we don't allow shareable with java inputstreams
+ BitmapRegionDecoder = doBuildTileIndex(env, stream, false);
+ stream->unref();
+ }
+ return BitmapRegionDecoder;
+}
+
+static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
+ jint native_asset, // Asset
+ jboolean isShareable) {
+ SkStream* stream;
+ Asset* asset = reinterpret_cast<Asset*>(native_asset);
+ stream = new AssetStreamAdaptor(asset);
+ SkAutoUnref aur(stream);
+ if (isShareable) {
+ aur.detach();
+ }
+ return doBuildTileIndex(env, stream, isShareable);
+}
+
+/*
+ * nine patch not supported
+ *
+ * purgeable not supported
+ * reportSizeToVM not supported
+ */
+static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd,
+ int start_x, int start_y, int width, int height, jobject options) {
+ SkImageDecoder *decoder = brd->getDecoder();
+ int sampleSize = 1;
+ SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
+ bool doDither = true;
+
+ if (NULL != options) {
+ sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
+ // initialize these, in case we fail later on
+ env->SetIntField(options, gOptions_widthFieldID, -1);
+ env->SetIntField(options, gOptions_heightFieldID, -1);
+ env->SetObjectField(options, gOptions_mimeFieldID, 0);
+
+ jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
+ prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
+ doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
+ }
+
+ decoder->setDitherImage(doDither);
+ SkBitmap* bitmap = new SkBitmap;
+ SkAutoTDelete<SkBitmap> adb(bitmap);
+ AutoDecoderCancel adc(options, decoder);
+
+ // To fix the race condition in case "requestCancelDecode"
+ // happens earlier than AutoDecoderCancel object is added
+ // to the gAutoDecoderCancelMutex linked list.
+ if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
+ return nullObjectReturn("gOptions_mCancelID");;
+ }
+
+ SkIRect region;
+ region.fLeft = start_x;
+ region.fTop = start_y;
+ region.fRight = start_x + width;
+ region.fBottom = start_y + height;
+
+ if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
+ return nullObjectReturn("decoder->decodeRegion returned false");
+ }
+
+ // update options (if any)
+ if (NULL != options) {
+ env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
+ env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
+ // TODO: set the mimeType field with the data from the codec.
+ // but how to reuse a set of strings, rather than allocating new one
+ // each time?
+ env->SetObjectField(options, gOptions_mimeFieldID,
+ getMimeTypeString(env, decoder->getFormat()));
+ }
+
+ // detach bitmap from its autotdeleter, since we want to own it now
+ adb.detach();
+
+ SkPixelRef* pr;
+ pr = bitmap->pixelRef();
+ // promise we will never change our pixels (great for sharing and pictures)
+ pr->setImmutable();
+ // now create the java bitmap
+ return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
+}
+
+static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+ return brd->getHeight();
+}
+
+static int nativeGetWidth(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+ return brd->getWidth();
+}
+
+static void nativeClean(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+ delete brd;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gBitmapRegionDecoderMethods[] = {
+ { "nativeDecodeRegion",
+ "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+ (void*)nativeDecodeRegion},
+
+ { "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
+
+ { "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
+
+ { "nativeClean", "(I)V", (void*)nativeClean},
+
+ { "nativeNewInstance",
+ "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromByteArray
+ },
+
+ { "nativeNewInstance",
+ "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromStream
+ },
+
+ { "nativeNewInstance",
+ "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromFileDescriptor
+ },
+
+ { "nativeNewInstance",
+ "(IZ)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromAsset
+ },
+};
+
+#define kClassPathName "android/graphics/BitmapRegionDecoder"
+
+int register_android_graphics_BitmapRegionDecoder(JNIEnv* env);
+int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
+{
+ return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+ gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
+}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 578de6f..b520c30 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -169,8 +169,8 @@
static jclass gBitmapConfig_class;
static jfieldID gBitmapConfig_nativeInstanceID;
-static jclass gLargeBitmap_class;
-static jmethodID gLargeBitmap_constructorMethodID;
+static jclass gBitmapRegionDecoder_class;
+static jmethodID gBitmapRegionDecoder_constructorMethodID;
static jclass gCanvas_class;
static jfieldID gCanvas_nativeInstanceID;
@@ -377,17 +377,18 @@
}
return obj;
}
-jobject GraphicsJNI::createLargeBitmap(JNIEnv* env, SkLargeBitmap* bitmap)
+
+jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
{
SkASSERT(bitmap != NULL);
- jobject obj = env->AllocObject(gLargeBitmap_class);
+ jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
if (hasException(env)) {
obj = NULL;
return obj;
}
if (obj) {
- env->CallVoidMethod(obj, gLargeBitmap_constructorMethodID, (jint)bitmap);
+ env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
if (hasException(env)) {
obj = NULL;
}
@@ -613,8 +614,8 @@
gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
"(IZ[BI)V");
- gLargeBitmap_class = make_globalref(env, "android/graphics/LargeBitmap");
- gLargeBitmap_constructorMethodID = env->GetMethodID(gLargeBitmap_class, "<init>", "(I)V");
+ gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
+ gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
@@ -654,4 +655,3 @@
return 0;
}
-
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 1a43a3e..d0f9125 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -4,7 +4,7 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkBitmap.h"
-#include "../images/SkLargeBitmap.h"
+#include "../images/SkBitmapRegionDecoder.h"
#include "../images/SkImageDecoder.h"
#include <jni.h>
@@ -56,7 +56,7 @@
static jobject createRegion(JNIEnv* env, SkRegion* region);
- static jobject createLargeBitmap(JNIEnv* env, SkLargeBitmap* bitmap);
+ static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
/** Set a pixelref for the bitmap (needs setConfig to already be called)
Returns true on success. If it returns false, then it failed, and the
@@ -181,4 +181,3 @@
do { if (NULL == (object)) { doThrowNPE(env); return; } } while (0)
#endif
-
diff --git a/core/jni/android/graphics/LargeBitmap.cpp b/core/jni/android/graphics/LargeBitmap.cpp
deleted file mode 100644
index 4cf5dfa..0000000
--- a/core/jni/android/graphics/LargeBitmap.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#define LOG_TAG "LargeBitmap"
-
-#include "SkBitmap.h"
-#include "SkImageEncoder.h"
-#include "SkColorPriv.h"
-#include "GraphicsJNI.h"
-#include "SkDither.h"
-#include "SkUnPreMultiply.h"
-#include "SkUtils.h"
-#include "SkTemplates.h"
-#include "SkPixelRef.h"
-#include "BitmapFactory.h"
-#include "AutoDecodeCancel.h"
-#include "SkLargeBitmap.h"
-
-#include <binder/Parcel.h>
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <jni.h>
-
-#if 0
- #define TRACE_BITMAP(code) code
-#else
- #define TRACE_BITMAP(code)
-#endif
-
-static jobject nullObjectReturn(const char msg[]) {
- if (msg) {
- SkDebugf("--- %s\n", msg);
- }
- return NULL;
-}
-
-/*
- * nine patch not supported
- *
- * purgeable not supported
- * reportSizeToVM not supported
- */
-static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkLargeBitmap *bm,
- int start_x, int start_y, int width, int height, jobject options) {
- SkImageDecoder *decoder = bm->getDecoder();
- int sampleSize = 1;
- SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
- bool doDither = true;
-
- if (NULL != options) {
- sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
- // initialize these, in case we fail later on
- env->SetIntField(options, gOptions_widthFieldID, -1);
- env->SetIntField(options, gOptions_heightFieldID, -1);
- env->SetObjectField(options, gOptions_mimeFieldID, 0);
-
- jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
- prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
- doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
- }
-
- decoder->setDitherImage(doDither);
- SkBitmap* bitmap = new SkBitmap;
- SkAutoTDelete<SkBitmap> adb(bitmap);
- AutoDecoderCancel adc(options, decoder);
-
- // To fix the race condition in case "requestCancelDecode"
- // happens earlier than AutoDecoderCancel object is added
- // to the gAutoDecoderCancelMutex linked list.
- if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
- return nullObjectReturn("gOptions_mCancelID");;
- }
-
- SkIRect region;
- region.fLeft = start_x;
- region.fTop = start_y;
- region.fRight = start_x + width;
- region.fBottom = start_y + height;
-
- if (!bm->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
- return nullObjectReturn("decoder->decodeRegion returned false");
- }
-
- // update options (if any)
- if (NULL != options) {
- env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
- env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
- // TODO: set the mimeType field with the data from the codec.
- // but how to reuse a set of strings, rather than allocating new one
- // each time?
- env->SetObjectField(options, gOptions_mimeFieldID,
- getMimeTypeString(env, decoder->getFormat()));
- }
-
- // detach bitmap from its autotdeleter, since we want to own it now
- adb.detach();
-
- SkPixelRef* pr;
- pr = bitmap->pixelRef();
- // promise we will never change our pixels (great for sharing and pictures)
- pr->setImmutable();
- // now create the java bitmap
- return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
-}
-
-static int nativeGetHeight(JNIEnv* env, jobject, SkLargeBitmap *bm) {
- return bm->getHeight();
-}
-
-static int nativeGetWidth(JNIEnv* env, jobject, SkLargeBitmap *bm) {
- return bm->getWidth();
-}
-
-static void nativeClean(JNIEnv* env, jobject, SkLargeBitmap *bm) {
- delete bm;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gLargeBitmapMethods[] = {
- { "nativeDecodeRegion",
- "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
- (void*)nativeDecodeRegion},
- { "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
- { "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
- { "nativeClean", "(I)V", (void*)nativeClean},
-};
-
-#define kClassPathName "android/graphics/LargeBitmap"
-
-int register_android_graphics_LargeBitmap(JNIEnv* env);
-int register_android_graphics_LargeBitmap(JNIEnv* env)
-{
- return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
- gLargeBitmapMethods, SK_ARRAY_COUNT(gLargeBitmapMethods));
-}
-
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
new file mode 100644
index 0000000..b6ead19
--- /dev/null
+++ b/core/jni/android/graphics/Utils.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Utils.h"
+#include "SkUtils.h"
+
+using namespace android;
+
+bool AssetStreamAdaptor::rewind() {
+ off_t pos = fAsset->seek(0, SEEK_SET);
+ if (pos == (off_t)-1) {
+ SkDebugf("----- fAsset->seek(rewind) failed\n");
+ return false;
+ }
+ return true;
+}
+
+size_t AssetStreamAdaptor::read(void* buffer, size_t size) {
+ ssize_t amount;
+
+ if (NULL == buffer) {
+ if (0 == size) { // caller is asking us for our total length
+ return fAsset->getLength();
+ }
+ // asset->seek returns new total offset
+ // we want to return amount that was skipped
+
+ off_t oldOffset = fAsset->seek(0, SEEK_CUR);
+ if (-1 == oldOffset) {
+ SkDebugf("---- fAsset->seek(oldOffset) failed\n");
+ return 0;
+ }
+ off_t newOffset = fAsset->seek(size, SEEK_CUR);
+ if (-1 == newOffset) {
+ SkDebugf("---- fAsset->seek(%d) failed\n", size);
+ return 0;
+ }
+ amount = newOffset - oldOffset;
+ } else {
+ amount = fAsset->read(buffer, size);
+ if (amount <= 0) {
+ SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount);
+ }
+ }
+
+ if (amount < 0) {
+ amount = 0;
+ }
+ return amount;
+}
+
+jobject android::nullObjectReturn(const char msg[]) {
+ if (msg) {
+ SkDebugf("--- %s\n", msg);
+ }
+ return NULL;
+}
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
new file mode 100644
index 0000000..2de41a1
--- /dev/null
+++ b/core/jni/android/graphics/Utils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef UTILS_DEFINED
+#define UTILS_DEFINED
+
+#include "SkStream.h"
+
+#include "android_util_Binder.h"
+
+#include <jni.h>
+#include <utils/Asset.h>
+
+namespace android {
+
+class AssetStreamAdaptor : public SkStream {
+public:
+ AssetStreamAdaptor(Asset* a) : fAsset(a) {}
+ virtual bool rewind();
+ virtual size_t read(void* buffer, size_t size);
+
+private:
+ Asset* fAsset;
+};
+
+
+/** Restore the file descriptor's offset in our destructor
+ */
+class AutoFDSeek {
+public:
+ AutoFDSeek(int fd) : fFD(fd) {
+ fCurr = ::lseek(fd, 0, SEEK_CUR);
+ }
+ ~AutoFDSeek() {
+ if (fCurr >= 0) {
+ ::lseek(fFD, fCurr, SEEK_SET);
+ }
+ }
+private:
+ int fFD;
+ off_t fCurr;
+};
+
+jobject nullObjectReturn(const char msg[]);
+
+}; // namespace android
+
+#endif
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 0932473a..2517a8a 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -127,12 +127,13 @@
close(mDispatchKeyWrite);
}
-void AInputQueue::attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data) {
+void AInputQueue::attachLooper(ALooper* looper, int ident,
+ ALooper_callbackFunc* callback, void* data) {
mPollLoop = static_cast<android::PollLoop*>(looper);
mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
- POLLIN, callback, data);
+ ident, POLLIN, callback, data);
mPollLoop->setLooperCallback(mDispatchKeyRead,
- POLLIN, callback, data);
+ ident, POLLIN, callback, data);
}
void AInputQueue::detachLooper() {
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 4b3f1c0..36e9089 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -593,6 +593,9 @@
case SQLITE_MISMATCH:
exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
break;
+ case SQLITE_UNCLOSED:
+ exceptionClass = "android/database/sqlite/SQLiteUnfinalizedObjectsException";
+ break;
default:
exceptionClass = "android/database/sqlite/SQLiteException";
break;
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7c99271..7dfb716 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -261,8 +261,7 @@
continue;
}
- if (set_sched_policy(t_pid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
- SP_BACKGROUND : SP_FOREGROUND)) {
+ if (androidSetThreadSchedulingGroup(t_pid, grp) != NO_ERROR) {
signalExceptionForGroupError(env, clazz, errno);
break;
}
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1951d14..8594027 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1265,7 +1265,13 @@
<public type="drawable" name="presence_audio_online" id="0x010800b1" />
<public-padding type="drawable" name="kraken_resource_pad" end="0x01080100" />
+ <public type="style" name="TextAppearance.StatusBar.Title" id="0x01030065" />
+ <public type="style" name="TextAppearance.StatusBar.Icon" id="0x01030066" />
+ <public type="style" name="TextAppearance.StatusBar.EventContent" id="0x01030067" />
+ <public type="style" name="TextAppearance.StatusBar.EventContent.Title" id="0x01030068" />
+
<public-padding type="style" name="kraken_resource_pad" end="0x01030090" />
+
<public-padding type="string" name="kraken_resource_pad" end="0x01040020" />
<public-padding type="integer" name="kraken_resource_pad" end="0x010e0010" />
<public-padding type="layout" name="kraken_resource_pad" end="0x01090020" />
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
new file mode 100644
index 0000000..cd2005d
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabaseTest.ClassToTestSqlCompilationAndCaching;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.File;
+
+public class SQLiteUnfinalizedExceptionTest extends AndroidTestCase {
+ private SQLiteDatabase mDatabase;
+ private File mDatabaseFile;
+ private static final String TABLE_NAME = "testCursor";
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
+ mDatabaseFile = new File(dbDir, "UnfinalizedExceptionTest.db");
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+ assertNotNull(mDatabase);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mDatabase.close();
+ mDatabaseFile.delete();
+ super.tearDown();
+ }
+
+ @SmallTest
+ public void testUnfinalizedExceptionNotExcpected() {
+ mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
+ // the above statement should be in SQLiteDatabase.mPrograms
+ // and should automatically be finalized when database is closed
+ mDatabase.lock();
+ try {
+ mDatabase.closeDatabase();
+ } finally {
+ mDatabase.unlock();
+ }
+ }
+
+ @SmallTest
+ public void testUnfinalizedException() {
+ mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
+ mDatabase.lock();
+ mDatabase.closePendingStatements(); // clears the above from finalizer queue in mdatabase
+ mDatabase.unlock();
+ ClassToTestSqlCompilationAndCaching.create(mDatabase, "select * from " + TABLE_NAME);
+ // since the above is NOT closed, closing database should fail
+ mDatabase.lock();
+ try {
+ mDatabase.closeDatabase();
+ fail("exception expected");
+ } catch (SQLiteUnfinalizedObjectsException e) {
+ // expected
+ } finally {
+ mDatabase.unlock();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 60c3c76..c8ad60d 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -285,6 +285,7 @@
assertEquals("d", uri.getQueryParameter("c"));
}
+ // http://b/2337042
@SmallTest
public void testHostWithTrailingDot() {
Uri uri = Uri.parse("http://google.com./b/c/g");
diff --git a/core/tests/coretests/src/android/net/WebAddressTest.java b/core/tests/coretests/src/android/net/WebAddressTest.java
index 7ca1e62..f0af35d 100644
--- a/core/tests/coretests/src/android/net/WebAddressTest.java
+++ b/core/tests/coretests/src/android/net/WebAddressTest.java
@@ -22,10 +22,19 @@
public class WebAddressTest extends TestCase {
+ // http://b/2337042
@SmallTest
public void testHostWithTrailingDot() {
WebAddress webAddress = new WebAddress("http://google.com./b/c/g");
assertEquals("google.com.", webAddress.mHost);
assertEquals("/b/c/g", webAddress.mPath);
}
+
+ // http://b/1011602
+ @SmallTest
+ public void testPathWithoutLeadingSlash() {
+ WebAddress webAddress = new WebAddress("http://www.myspace.com?si=1");
+ assertEquals("www.myspace.com", webAddress.mHost);
+ assertEquals("/?si=1", webAddress.mPath);
+ }
}
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index f22d2d3..56872a7 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -42,188 +42,39 @@
<h2 id="optimize_judiciously">Optimize Judiciously</h2>
-<p>As you get started thinking about how to design your application, and as
-you write it, consider
-the cautionary points about optimization that Josh Bloch makes in his book
-<em>Effective Java</em>. Here's "Item 47: Optimize Judiciously", excerpted from
-the latest edition of the book with permission. Although Josh didn't have
-Android application development in mind when writing this section — for
-example, the <code style="color:black">java.awt.Component</code> class
-referenced is not available in Android, and Android uses the
-Dalvik VM, rather than a standard JVM — his points are still valid. </p>
+<p>This document is about Android-specific micro-optimization, so it assumes
+that you've already used profiling to work out exactly what code needs to be
+optimized, and that you already have a way to measure the effect (good or bad)
+of any changes you make. You only have so much engineering time to invest, so
+it's important to know you're spending it wisely.
-<blockquote>
+<p>(See <a href="#closing_notes">Closing Notes</a> for more on profiling and
+writing effective benchmarks.)
-<p>There are three aphorisms concerning optimization that everyone should know.
-They are perhaps beginning to suffer from overexposure, but in case you aren't
-yet familiar with them, here they are:</p>
+<p>This document also assumes that you made the best decisions about data
+structures and algorithms, and that you've also considered the future
+performance consequences of your API decisions. Using the right data
+structures and algorithms will make more difference than any of the advice
+here, and considering the performance consequences of your API decisions will
+make it easier to switch to better implementations later (this is more
+important for library code than for application code).
-<div style="padding-left:3em;padding-right:4em;">
+<p>(If you need that kind of advice, see Josh Bloch's <em>Effective Java</em>,
+item 47.)</p>
-<p style="margin-bottom:.5em;">More computing sins are committed in the name of
-efficiency (without necessarily achieving it) than for any other single
-reason—including blind stupidity.</p>
-<p>—William A. Wulf <span style="font-size:80%;"><sup>1</sup></span></p>
+<p>One of the trickiest problems you'll face when micro-optimizing an Android
+app is that your app is pretty much guaranteed to be running on multiple
+hardware platforms. Different versions of the VM running on different
+processors running at different speeds. It's not even generally the case
+that you can simply say "device X is a factor F faster/slower than device Y",
+and scale your results from one device to others. In particular, measurement
+on the emulator tells you very little about performance on any device. There
+are also huge differences between devices with and without a JIT: the "best"
+code for a device with a JIT is not always the best code for a device
+without.</p>
-<p style="margin-bottom:.5em;">We should forget about small efficiencies, say
-about 97% of the time: premature optimization is the root of all evil. </p>
-<p>—Donald E. Knuth <span style="font-size:80%;"><sup>2</sup></span></p>
-
-
-<p style="margin-bottom:.5em;">We follow two rules in the matter of optimization:</p>
-<ul style="margin-bottom:0">
-<li>Rule 1. Don't do it.</li>
-<li>Rule 2 (for experts only). Don't do it yet — that is, not until you have a
-perfectly clear and unoptimized solution. </li>
-</ul>
-<p>—M. A. Jackson <span style="font-size:80%;"><sup>3</sup></span></p>
-</div>
-
-<p>All of these aphorisms predate the Java programming language by two decades.
-They tell a deep truth about optimization: it is easy to do more harm than good,
-especially if you optimize prematurely. In the process, you may produce software
-that is neither fast nor correct and cannot easily be fixed.</p>
-
-<p>Don't sacrifice sound architectural principles for performance.
-<strong>Strive to write good programs rather than fast ones.</strong> If a good
-program is not fast enough, its architecture will allow it to be optimized. Good
-programs embody the principle of <em>information hiding</em>: where possible,
-they localize design decisions within individual modules, so individual
-decisions can be changed without affecting the remainder of the system (Item
-13).</p>
-
-<p>This does <em>not</em> mean that you can ignore performance concerns until
-your program is complete. Implementation problems can be fixed by later
-optimization, but pervasive architectural flaws that limit performance can be
-impossible to fix without rewriting the system. Changing a fundamental facet of
-your design after the fact can result in an ill-structured system that is
-difficult to maintain and evolve. Therefore you must think about performance
-during the design process.</p>
-
-<p><strong>Strive to avoid design decisions that limit performance.</strong> The
-components of a design that are most difficult to change after the fact are
-those specifying interactions between modules and with the outside world. Chief
-among these design components are APIs, wire-level protocols, and persistent
-data formats. Not only are these design components difficult or impossible to
-change after the fact, but all of them can place significant limitations on the
-performance that a system can ever achieve.</p>
-
-<p><strong>Consider the performance consequences of your API design
-decisions.</strong> Making a public type mutable may require a lot of needless
-defensive copying (Item 39). Similarly, using inheritance in a public class
-where composition would have been appropriate ties the class forever to its
-superclass, which can place artificial limits on the performance of the subclass
-(Item 16). As a final example, using an implementation type rather than an
-interface in an API ties you to a specific implementation, even though faster
-implementations may be written in the future (Item 52).</p>
-
-<p>The effects of API design on performance are very real. Consider the <code
-style="color:black">getSize</code> method in the <code
-style="color:black">java.awt.Component</code> class. The decision that this
-performance-critical method was to return a <code
-style="color:black">Dimension</code> instance, coupled with the decision that
-<code style="color:black">Dimension</code> instances are mutable, forces any
-implementation of this method to allocate a new <code
-style="color:black">Dimension</code> instance on every invocation. Even though
-allocating small objects is inexpensive on a modern VM, allocating millions of
-objects needlessly can do real harm to performance.</p>
-
-<p>In this case, several alternatives existed. Ideally, <code
-style="color:black">Dimension</code> should have been immutable (Item 15);
-alternatively, the <code style="color:black">getSize</code> method could have
-been replaced by two methods returning the individual primitive components of a
-<code style="color:black">Dimension</code> object. In fact, two such methods
-were added to the Component API in the 1.2 release for performance reasons.
-Preexisting client code, however, still uses the <code
-style="color:black">getSize</code> method and still suffers the performance
-consequences of the original API design decisions.</p>
-
-<p>Luckily, it is generally the case that good API design is consistent with
-good performance. <strong>It is a very bad idea to warp an API to achieve good
-performance.</strong> The performance issue that caused you to warp the API may
-go away in a future release of the platform or other underlying software, but
-the warped API and the support headaches that come with it will be with you for
-life.</p>
-
-<p>Once you've carefully designed your program and produced a clear, concise,
-and well-structured implementation, <em>then</em> it may be time to consider
-optimization, assuming you're not already satisfied with the performance of the
-program.</p>
-
-<p>Recall that Jackson's two rules of optimization were "Don't do it," and "(for
-experts only). Don't do it yet." He could have added one more: <strong>measure
-performance before and after each attempted optimization.</strong> You may be
-surprised by what you find. Often, attempted optimizations have no measurable
-effect on performance; sometimes, they make it worse. The main reason is that
-it's difficult to guess where your program is spending its time. The part of the
-program that you think is slow may not be at fault, in which case you'd be
-wasting your time trying to optimize it. Common wisdom says that programs spend
-80 percent of their time in 20 percent of their code.</p>
-
-<p>Profiling tools can help you decide where to focus your optimization efforts.
-Such tools give you runtime information, such as roughly how much time each
-method is consuming and how many times it is invoked. In addition to focusing
-your tuning efforts, this can alert you to the need for algorithmic changes. If
-a quadratic (or worse) algorithm lurks inside your program, no amount of tuning
-will fix the problem. You must replace the algorithm with one that is more
-efficient. The more code in the system, the more important it is to use a
-profiler. It's like looking for a needle in a haystack: the bigger the haystack,
-the more useful it is to have a metal detector. The JDK comes with a simple
-profiler and modern IDEs provide more sophisticated profiling tools.</p>
-
-<p>The need to measure the effects of attempted optimization is even greater on
-the Java platform than on more traditional platforms, because the Java
-programming language does not have a strong <em>performance model</em>. The
-relative costs of the various primitive operations are not well defined. The
-"semantic gap" between what the programmer writes and what the CPU executes is
-far greater than in traditional statically compiled languages, which makes it
-very difficult to reliably predict the performance consequences of any
-optimization. There are plenty of performance myths floating around that turn
-out to be half-truths or outright lies.</p>
-
-<p>Not only is Java's performance model ill-defined, but it varies from JVM
-implementation to JVM implementation, from release to release, and from
-processor to processor. If you will be running your program on multiple JVM
-implementations or multiple hardware platforms, it is important that you measure
-the effects of your optimization on each. Occasionally you may be forced to make
-trade-offs between performance on different JVM implementations or hardware
-platforms.</p>
-
-<p>To summarize, do not strive to write fast programs — strive to write
-good ones; speed will follow. Do think about performance issues while you're
-designing systems and especially while you're designing APIs, wire-level
-protocols, and persistent data formats. When you've finished building the
-system, measure its performance. If it's fast enough, you're done. If not,
-locate the source of the problems with the aid of a profiler, and go to work
-optimizing the relevant parts of the system. The first step is to examine your
-choice of algorithms: no amount of low-level optimization can make up for a poor
-choice of algorithm. Repeat this process as necessary, measuring the performance
-after every change, until you're satisfied.</p>
-
-<p>—Excerpted from Josh Bloch's <em>Effective Java</em>, Second Ed.
-(Addison-Wesley, 2008).</em></p>
-
-<p style="font-size:80%;margin-bottom:0;"><sup>1</sup> Wulf, W. A Case Against
-the GOTO. <em>Proceedings of the 25th ACM National
-Conference</em> 2 (1972): 791–797.</p>
-<p style="font-size:80%;margin-bottom:0;"><sup>2</sup> Knuth, Donald. Structured
-Programming with go to Statements. <em>Computing
-Surveys 6</em> (1974): 261–301.</p>
-<p style="font-size:80%"><sup>3</sup> Jackson, M. A. <em>Principles of Program
-Design</em>, Academic Press, London, 1975.
-ISBN: 0123790506.</p>
-
-</blockquote>
-
-<p>One of the trickiest problems you'll face when micro-optimizing Android
-apps is that the "if you will be running your program on ... multiple hardware
-platforms" clause above is always true. And it's not even generally the case
-that you can say "device X is a factor F faster/slower than device Y".
-This is especially true if one of the devices is the emulator, or one of the
-devices has a JIT. If you want to know how your app performs on a given device,
-you need to test it on that device. Drawing conclusions from the emulator is
-particularly dangerous, as is attempting to compare JIT versus non-JIT
-performance: the performance <em>profiles</em> can differ wildly.</p>
+<p>If you want to know how your app performs on a given device, you need to
+test on that device.</p>
<a name="object_creation"></a>
<h2>Avoid Creating Objects</h2>
@@ -566,3 +417,11 @@
not measuring what you think you're measuring (because, say, the VM has
managed to optimize all your code away). We highly recommend you use Caliper
to run your own microbenchmarks.</p>
+
+<p>You may also find
+<a href="{@docRoot}guide/developing/tools/traceview.html">Traceview</a> useful
+for profiling, but it's important to realize that it currently disables the JIT,
+which may cause it to misattribute time to code that the JIT may be able to win
+back. It's especially important after making changes suggested by Traceview
+data to ensure that the resulting code actually runs faster when run without
+Traceview.
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
new file mode 100644
index 0000000..bc92b05
--- /dev/null
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -0,0 +1,270 @@
+/* Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.content.res.AssetManager;
+import android.os.MemoryFile;
+
+import java.io.BufferedInputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * BitmapRegionDecoder can be used to decode a rectangle region from an image.
+ * BitmapRegionDecoder is particularly useful when an original image is large and
+ * you only need parts of the image.
+ *
+ * <p>To create a BitmapRegionDecoder, call newInstance(...).
+ * Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly
+ * to get a decoded Bitmap of the specified region.
+ *
+ * @hide
+ */
+public final class BitmapRegionDecoder {
+ private int mNativeBitmapRegionDecoder;
+ private boolean mRecycled;
+
+ /**
+ * Create a BitmapRegionDecoder from the specified byte array.
+ * Currently only the Jpeg format is supported.
+ *
+ * @param data byte array of compressed image data.
+ * @param offset offset into data for where the decoder should begin
+ * parsing.
+ * @param length the number of bytes, beginning at offset, to parse
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(byte[] data,
+ int offset, int length, boolean isShareable) throws IOException {
+ if ((offset | length) < 0 || data.length < offset + length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return nativeNewInstance(data, offset, length, isShareable);
+ }
+
+ /**
+ * Create a BitmapRegionDecoder from the file descriptor.
+ * The position within the descriptor will not be changed when
+ * this returns, so the descriptor can be used again as is.
+ * Currently only the Jpeg format is supported.
+ *
+ * @param fd The file descriptor containing the data to decode
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(
+ FileDescriptor fd, boolean isShareable) throws IOException {
+ if (MemoryFile.isMemoryFile(fd)) {
+ int mappedlength = MemoryFile.getSize(fd);
+ MemoryFile file = new MemoryFile(fd, mappedlength, "r");
+ InputStream is = file.getInputStream();
+ return newInstance(is, isShareable);
+ }
+ return nativeNewInstance(fd, isShareable);
+ }
+
+ /**
+ * Create a BitmapRegionDecoder from an input stream.
+ * The stream's position will be where ever it was after the encoded data
+ * was read.
+ * Currently only the Jpeg format is supported.
+ *
+ * @param is The input stream that holds the raw data to be decoded into a
+ * BitmapRegionDecoder.
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(InputStream is,
+ boolean isShareable) throws IOException {
+ // we need mark/reset to work properly in JNI
+
+ if (!is.markSupported()) {
+ is = new BufferedInputStream(is, 16 * 1024);
+ }
+
+ if (is instanceof AssetManager.AssetInputStream) {
+ return nativeNewInstance(
+ ((AssetManager.AssetInputStream) is).getAssetInt(),
+ isShareable);
+ } else {
+ // pass some temp storage down to the native code. 1024 is made up,
+ // but should be large enough to avoid too many small calls back
+ // into is.read(...).
+ byte [] tempStorage = new byte[16 * 1024];
+ return nativeNewInstance(is, tempStorage, isShareable);
+ }
+ }
+
+ /**
+ * Create a BitmapRegionDecoder from a file path.
+ * Currently only the Jpeg format is supported.
+ *
+ * @param pathName complete path name for the file to be decoded.
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(String pathName,
+ boolean isShareable) throws IOException {
+ BitmapRegionDecoder decoder = null;
+ InputStream stream = null;
+
+ try {
+ stream = new FileInputStream(pathName);
+ decoder = newInstance(stream, isShareable);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // do nothing here
+ }
+ }
+ }
+ return decoder;
+ }
+
+ /* Private constructor that must receive an already allocated native
+ region decoder int (pointer).
+
+ This can be called from JNI code.
+ */
+ private BitmapRegionDecoder(int decoder) {
+ mNativeBitmapRegionDecoder = decoder;
+ mRecycled = false;
+ }
+
+ /**
+ * Decodes a rectangle region in the image specified by rect.
+ *
+ * @param rect The rectangle that specified the region to be decode.
+ * @param options null-ok; Options that control downsampling.
+ * inPurgeable is not supported.
+ * @return The decoded bitmap, or null if the image data could not be
+ * decoded.
+ */
+ public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
+ checkRecycled("decodeRegion called on recycled region decoder");
+ if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
+ || rect.bottom > getHeight())
+ throw new IllegalArgumentException("rectangle is not inside the image");
+ return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top, options);
+ }
+
+ /** Returns the original image's width */
+ public int getWidth() {
+ checkRecycled("getWidth called on recycled region decoder");
+ return nativeGetWidth(mNativeBitmapRegionDecoder);
+ }
+
+ /** Returns the original image's height */
+ public int getHeight() {
+ checkRecycled("getHeight called on recycled region decoder");
+ return nativeGetHeight(mNativeBitmapRegionDecoder);
+ }
+
+ /**
+ * Frees up the memory associated with this region decoder, and mark the
+ * region decoder as "dead", meaning it will throw an exception if decodeRegion(),
+ * getWidth() or getHeight() is called.
+ *
+ * <p>This operation cannot be reversed, so it should only be called if you are
+ * sure there are no further uses for the region decoder. This is an advanced call,
+ * and normally need not be called, since the normal GC process will free up this
+ * memory when there are no more references to this region decoder.
+ */
+ public void recycle() {
+ if (!mRecycled) {
+ nativeClean(mNativeBitmapRegionDecoder);
+ mRecycled = true;
+ }
+ }
+
+ /**
+ * Returns true if this region decoder has been recycled.
+ * If so, then it is an error to try use its method.
+ *
+ * @return true if the region decoder has been recycled
+ */
+ public final boolean isRecycled() {
+ return mRecycled;
+ }
+
+ /**
+ * Called by methods that want to throw an exception if the region decoder
+ * has already been recycled.
+ */
+ private void checkRecycled(String errorMessage) {
+ if (mRecycled) {
+ throw new IllegalStateException(errorMessage);
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ recycle();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private static native Bitmap nativeDecodeRegion(int lbm,
+ int start_x, int start_y, int width, int height,
+ BitmapFactory.Options options);
+ private static native int nativeGetWidth(int lbm);
+ private static native int nativeGetHeight(int lbm);
+ private static native void nativeClean(int lbm);
+
+ private static native BitmapRegionDecoder nativeNewInstance(
+ byte[] data, int offset, int length, boolean isShareable);
+ private static native BitmapRegionDecoder nativeNewInstance(
+ FileDescriptor fd, boolean isShareable);
+ private static native BitmapRegionDecoder nativeNewInstance(
+ InputStream is, byte[] storage, boolean isShareable);
+ private static native BitmapRegionDecoder nativeNewInstance(
+ int asset, boolean isShareable);
+}
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index ed09f89..05b2d60 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -27,6 +27,7 @@
int mSize;
Element[] mElements;
String[] mElementNames;
+ int[] mArraySizes;
DataType mType;
DataKind mKind;
@@ -313,11 +314,12 @@
return rs.mElement_MATRIX_2X2;
}
- Element(int id, RenderScript rs, Element[] e, String[] n) {
+ Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
super(id, rs);
mSize = 0;
mElements = e;
mElementNames = n;
+ mArraySizes = as;
for (int ct = 0; ct < mElements.length; ct++ ) {
mSize += mElements[ct].mSize;
}
@@ -441,6 +443,7 @@
RenderScript mRS;
Element[] mElements;
String[] mElementNames;
+ int[] mArraySizes;
int mCount;
public Builder(RenderScript rs) {
@@ -448,35 +451,49 @@
mCount = 0;
mElements = new Element[8];
mElementNames = new String[8];
+ mArraySizes = new int[8];
}
- public void add(Element element, String name) {
+ public void add(Element element, String name, int arraySize) {
+ if (arraySize < 1) {
+ throw new IllegalArgumentException("Array size cannot be less than 1.");
+ }
if(mCount == mElements.length) {
Element[] e = new Element[mCount + 8];
String[] s = new String[mCount + 8];
+ int[] as = new int[mCount + 8];
System.arraycopy(mElements, 0, e, 0, mCount);
System.arraycopy(mElementNames, 0, s, 0, mCount);
+ System.arraycopy(mArraySizes, 0, as, 0, mCount);
mElements = e;
mElementNames = s;
+ mArraySizes = as;
}
mElements[mCount] = element;
mElementNames[mCount] = name;
+ mArraySizes[mCount] = arraySize;
mCount++;
}
+ public void add(Element element, String name) {
+ add(element, name, 1);
+ }
+
public Element create() {
mRS.validate();
Element[] ein = new Element[mCount];
String[] sin = new String[mCount];
+ int[] asin = new int[mCount];
java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
+ java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
int[] ids = new int[ein.length];
for (int ct = 0; ct < ein.length; ct++ ) {
ids[ct] = ein[ct].mID;
}
- int id = mRS.nElementCreate2(ids, sin);
- return new Element(id, mRS, ein, sin);
+ int id = mRS.nElementCreate2(ids, sin, asin);
+ return new Element(id, mRS, ein, sin, asin);
}
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 62d70a7..1f3e159 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -152,9 +152,9 @@
synchronized int nElementCreate(int type, int kind, boolean norm, int vecSize) {
return rsnElementCreate(mContext, type, kind, norm, vecSize);
}
- native int rsnElementCreate2(int con, int[] elements, String[] names);
- synchronized int nElementCreate2(int[] elements, String[] names) {
- return rsnElementCreate2(mContext, elements, names);
+ native int rsnElementCreate2(int con, int[] elements, String[] names, int[] arraySizes);
+ synchronized int nElementCreate2(int[] elements, String[] names, int[] arraySizes) {
+ return rsnElementCreate2(mContext, elements, names, arraySizes);
}
native void rsnElementGetNativeData(int con, int id, int[] elementData);
synchronized void nElementGetNativeData(int id, int[] elementData) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index c8e6656..f07dbfd8 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -253,12 +253,13 @@
}
static jint
-nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names)
+nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names, jintArray _arraySizes)
{
int fieldCount = _env->GetArrayLength(_ids);
LOG_API("nElementCreate2, con(%p)", con);
jint *ids = _env->GetIntArrayElements(_ids, NULL);
+ jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *));
size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t));
@@ -267,12 +268,13 @@
nameArray[ct] = _env->GetStringUTFChars(s, NULL);
sizeArray[ct] = _env->GetStringUTFLength(s);
}
- jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray);
+ jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray, (const uint32_t *)arraySizes);
for (int ct=0; ct < fieldCount; ct++) {
jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
_env->ReleaseStringUTFChars(s, nameArray[ct]);
}
_env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
+ _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
free(nameArray);
free(sizeArray);
return (jint)id;
@@ -1230,7 +1232,7 @@
{"rsnFontCreateFromFile", "(ILjava/lang/String;II)I", (void*)nFontCreateFromFile },
{"rsnElementCreate", "(IIIZI)I", (void*)nElementCreate },
-{"rsnElementCreate2", "(I[I[Ljava/lang/String;)I", (void*)nElementCreate2 },
+{"rsnElementCreate2", "(I[I[Ljava/lang/String;[I)I", (void*)nElementCreate2 },
{"rsnElementGetNativeData", "(II[I)V", (void*)nElementGetNativeData },
{"rsnElementGetSubElements", "(II[I[Ljava/lang/String;)V", (void*)nElementGetSubElements },
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index c388ba8..fdceb84 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -69,7 +69,7 @@
/* Destroys the consumer and releases its input channel. */
~AInputQueue();
- void attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data);
+ void attachLooper(ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
void detachLooper();
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index 81230e8..bc616eb 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -111,12 +111,18 @@
* This method can be called on any thread.
* This method may block briefly if it needs to wake the poll loop.
*/
- void setCallback(int fd, int events, Callback callback, void* data = NULL);
+ void setCallback(int fd, int ident, int events, Callback callback, void* data = NULL);
/**
+ * Convenience for above setCallback when ident is not used. In this case
+ * the ident is set to POLL_CALLBACK.
+ */
+ void setCallback(int fd, int events, Callback callback, void* data = NULL);
+
+ /**
* Like setCallback(), but for the NDK callback function.
*/
- void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+ void setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
void* data);
/**
@@ -153,11 +159,13 @@
struct RequestedCallback {
Callback callback;
ALooper_callbackFunc* looperCallback;
+ int ident;
void* data;
};
struct PendingCallback {
int fd;
+ int ident;
int events;
Callback callback;
ALooper_callbackFunc* looperCallback;
@@ -185,7 +193,7 @@
void openWakePipe();
void closeWakePipe();
- void setCallbackCommon(int fd, int events, Callback callback,
+ void setCallbackCommon(int fd, int ident, int events, Callback callback,
ALooper_callbackFunc* looperCallback, void* data);
ssize_t getRequestIndexLocked(int fd);
void wakeAndLock();
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index 3396f25..7eb6da5 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -86,7 +86,7 @@
Mutex::Autolock _l(mLock);
if (mPollLoop == 0) {
mPollLoop = new PollLoop(true);
- mPollLoop->setCallback(getFd(), POLLIN, NULL, NULL);
+ mPollLoop->setCallback(getFd(), getFd(), POLLIN, NULL, NULL);
}
return mPollLoop;
}
diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/libs/rs/java/ModelViewer/res/raw/robot.a3d
index 2d7d32b..f48895c 100644
--- a/libs/rs/java/ModelViewer/res/raw/robot.a3d
+++ b/libs/rs/java/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
index 9672a6a..85c1d42 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
@@ -105,7 +105,7 @@
bs.setMin(Sampler.Value.LINEAR);
bs.setMag(Sampler.Value.LINEAR);
bs.setWrapS(Sampler.Value.CLAMP);
- bs.setWrapT(Sampler.Value.WRAP);
+ bs.setWrapT(Sampler.Value.CLAMP);
mSampler = bs.create();
ProgramFragment.Builder b = new ProgramFragment.Builder(mRS);
@@ -123,7 +123,6 @@
mPVA = new ProgramVertex.MatrixAllocation(mRS);
mPVBackground.bindAllocation(mPVA);
- mPVA.setupProjectionNormalized(mWidth, mHeight);
mScript.set_gPVBackground(mPVBackground);
}
@@ -159,14 +158,14 @@
mGroup1.addChild(mRobot1);
mGroup1.addChild(mRobot2);
- mGroup1.setTransform(0, new Float4(0.0f, 0.0f, 5.0f, 0.0f), TransformType.TRANSLATE);
+ mGroup1.setTransform(0, new Float4(0.0f, 0.0f, -15.0f, 0.0f), TransformType.TRANSLATE);
mGroup1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 15.0f), TransformType.ROTATE);
- mRobot1.setTransform(0, new Float4(-2.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE);
+ mRobot1.setTransform(0, new Float4(-3.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE);
mRobot1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 20.0f), TransformType.ROTATE);
mRobot1.setTransform(2, new Float4(0.2f, 0.2f, 0.2f, 0.0f), TransformType.SCALE);
- mRobot2.setTransform(0, new Float4(2.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE);
+ mRobot2.setTransform(0, new Float4(3.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE);
mRobot2.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, -20.0f), TransformType.ROTATE);
mRobot2.setTransform(2, new Float4(0.3f, 0.3f, 0.3f, 0.0f), TransformType.SCALE);
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
index b8b0119..d8d1a6e 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
@@ -79,7 +79,7 @@
mRotation += 360;
}
- mScript.set_gRotate(-(float)mRotation);
+ mScript.set_gRotate((float)mRotation);
mLastX = x;
mLastY = y;
@@ -101,7 +101,7 @@
bs.setMin(Sampler.Value.LINEAR);
bs.setMag(Sampler.Value.LINEAR);
bs.setWrapS(Sampler.Value.CLAMP);
- bs.setWrapT(Sampler.Value.WRAP);
+ bs.setWrapT(Sampler.Value.CLAMP);
mSampler = bs.create();
ProgramFragment.Builder b = new ProgramFragment.Builder(mRS);
@@ -119,7 +119,6 @@
mPVA = new ProgramVertex.MatrixAllocation(mRS);
mPVBackground.bindAllocation(mPVA);
- mPVA.setupProjectionNormalized(mWidth, mHeight);
mScript.set_gPVBackground(mPVBackground);
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
index c794438..ce6bb1e 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
@@ -71,6 +71,10 @@
rsgClearDepth(1.0f);
rsgBindProgramVertex(gPVBackground);
+ rs_matrix4x4 proj;
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
rsgBindProgramFragment(gPFBackground);
rsgBindProgramStore(gPFSBackground);
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index adb609c..43be266 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -46,6 +46,10 @@
rsgClearDepth(1.0f);
rsgBindProgramVertex(gPVBackground);
+ rs_matrix4x4 proj;
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
rsgBindProgramFragment(gPFBackground);
rsgBindProgramStore(gPFSBackground);
@@ -54,9 +58,9 @@
rs_matrix4x4 matrix;
rsMatrixLoadIdentity(&matrix);
// Position our model on the screen
- rsMatrixTranslate(&matrix, 0.0f, -0.3f, 1.2f);
+ rsMatrixTranslate(&matrix, 0.0f, -0.3f, -10.0f);
rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
- rsMatrixRotate(&matrix, -25.0f, 1.0f, 0.0f, 0.0f);
+ rsMatrixRotate(&matrix, 25.0f, 1.0f, 0.0f, 0.0f);
rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f);
rsgProgramVertexLoadModelMatrix(&matrix);
diff --git a/libs/rs/java/Samples/res/raw/torus.a3d b/libs/rs/java/Samples/res/raw/torus.a3d
index d09bc13..0322b01 100644
--- a/libs/rs/java/Samples/res/raw/torus.a3d
+++ b/libs/rs/java/Samples/res/raw/torus.a3d
Binary files differ
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ad162bb..c7fb2af 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -80,6 +80,7 @@
param const RsElement * elements
param const char ** names
param const size_t * nameLengths
+ param const uint32_t * arraySize
ret RsElement
}
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 2602dd4..0b7bb27 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -65,7 +65,7 @@
size_t total = 0;
for (size_t ct=0; ct < mFieldCount; ct++) {
- total += mFields[ct].e->mBits;
+ total += mFields[ct].e->mBits * mFields[ct].arraySize;;
}
return total;
}
@@ -95,6 +95,7 @@
stream->addU32(mFieldCount);
for(uint32_t ct = 0; ct < mFieldCount; ct++) {
stream->addString(&mFields[ct].name);
+ stream->addU32(mFields[ct].arraySize);
mFields[ct].e->serialize(stream);
}
}
@@ -122,6 +123,7 @@
elem->mFields = new ElementField_t [elem->mFieldCount];
for(uint32_t ct = 0; ct < elem->mFieldCount; ct ++) {
stream->loadString(&elem->mFields[ct].name);
+ elem->mFields[ct].arraySize = stream->loadU32();
Element *fieldElem = Element::createFromStream(rsc, stream);
elem->mFields[ct].e.set(fieldElem);
elem->mFields[ct].offsetBits = offset;
@@ -155,7 +157,8 @@
for (uint32_t i=0; i < elem->mFieldCount; i++) {
if ((ee->mFields[i].e.get() != elem->mFields[i].e.get()) ||
(ee->mFields[i].name.length() != elem->mFields[i].name.length()) ||
- (ee->mFields[i].name != elem->mFields[i].name)) {
+ (ee->mFields[i].name != elem->mFields[i].name) ||
+ (ee->mFields[i].arraySize != elem->mFields[i].arraySize)) {
match = false;
break;
}
@@ -200,7 +203,7 @@
}
const Element * Element::create(Context *rsc, size_t count, const Element **ein,
- const char **nin, const size_t * lengths)
+ const char **nin, const size_t * lengths, const uint32_t *asin)
{
// Look for an existing match.
for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) {
@@ -210,7 +213,8 @@
for (uint32_t i=0; i < count; i++) {
if ((ee->mFields[i].e.get() != ein[i]) ||
(ee->mFields[i].name.length() != lengths[i]) ||
- (ee->mFields[i].name != nin[i])) {
+ (ee->mFields[i].name != nin[i]) ||
+ (ee->mFields[i].arraySize != asin[i])) {
match = false;
break;
}
@@ -230,6 +234,7 @@
e->mFields[ct].e.set(ein[ct]);
e->mFields[ct].name.setTo(nin[ct], lengths[ct]);
e->mFields[ct].offsetBits = bits;
+ e->mFields[ct].arraySize = asin[ct];
bits += ein[ct]->getSizeBits();
if (ein[ct]->mHasReference) {
@@ -274,7 +279,11 @@
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- mFields[i].e->incRefs(&p[mFields[i].offsetBits >> 3]);
+ p = &p[mFields[i].offsetBits >> 3];
+ for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
+ mFields[i].e->incRefs(p);
+ p += mFields[i].e->getSizeBytes();
+ }
}
}
}
@@ -293,7 +302,11 @@
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- mFields[i].e->decRefs(&p[mFields[i].offsetBits >> 3]);
+ p = &p[mFields[i].offsetBits >> 3];
+ for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
+ mFields[i].e->decRefs(p);
+ p += mFields[i].e->getSizeBytes();
+ }
}
}
}
@@ -331,10 +344,11 @@
size_t count,
const RsElement * ein,
const char ** names,
- const size_t * nameLengths)
+ const size_t * nameLengths,
+ const uint32_t * arraySizes)
{
//LOGE("rsi_ElementCreate2 %i", count);
- const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths);
+ const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths, arraySizes);
e->incUserRef();
return (RsElement)e;
}
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index b5dad7a2..42eef4a 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -66,7 +66,7 @@
static const Element * create(Context *rsc, RsDataType dt, RsDataKind dk,
bool isNorm, uint32_t vecSize);
static const Element * create(Context *rsc, size_t count, const Element **,
- const char **, const size_t * lengths);
+ const char **, const size_t * lengths, const uint32_t *asin);
void incRefs(const void *) const;
void decRefs(const void *) const;
@@ -80,6 +80,7 @@
String8 name;
ObjectBaseRef<const Element> e;
uint32_t offsetBits;
+ uint32_t arraySize;
} ElementField_t;
ElementField_t *mFields;
size_t mFieldCount;
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 7661d499..5889bfb 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -488,8 +488,9 @@
size_t lengths[2];
lengths[0] = posName.size();
lengths[1] = texName.size();
+ uint32_t arraySizes[2] = {1, 1};
- const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
+ const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
Type *vertexDataType = new Type(mRSC);
vertexDataType->setDimX(mMaxNumberOfQuads * 4);
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index a140e22..662791d 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -17,7 +17,7 @@
#include "rsContext.h"
#include "rsScriptC.h"
#include "rsMatrix.h"
-#include "../../../external/llvm/libbcc/include/bcc/bcc.h"
+#include "../../compile/libbcc/include/bcc/bcc.h"
#include "utils/Timers.h"
#include <GLES/gl.h>
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index f740fa0..6d3eeee 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -95,6 +95,7 @@
RequestedCallback requestedCallback;
requestedCallback.callback = NULL;
requestedCallback.looperCallback = NULL;
+ requestedCallback.ident = 0;
requestedCallback.data = NULL;
mRequestedCallbacks.insertAt(requestedCallback, 0);
}
@@ -116,7 +117,7 @@
mPendingFdsPos++;
if (outEvents != NULL) *outEvents = pending.events;
if (outData != NULL) *outData = pending.data;
- return pending.fd;
+ return pending.ident;
}
mLock.lock();
@@ -182,6 +183,7 @@
const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
PendingCallback pending;
pending.fd = requestedFd.fd;
+ pending.ident = requestedCallback.ident;
pending.events = revents;
pending.callback = requestedCallback.callback;
pending.looperCallback = requestedCallback.looperCallback;
@@ -191,7 +193,7 @@
mPendingCallbacks.push(pending);
} else if (pending.fd != mWakeReadPipeFd) {
if (result == POLL_CALLBACK) {
- result = pending.fd;
+ result = pending.ident;
if (outEvents != NULL) *outEvents = pending.events;
if (outData != NULL) *outData = pending.data;
} else {
@@ -268,16 +270,20 @@
return mAllowNonCallbacks;
}
+void PollLoop::setCallback(int fd, int ident, int events, Callback callback, void* data) {
+ setCallbackCommon(fd, ident, events, callback, NULL, data);
+}
+
void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
- setCallbackCommon(fd, events, callback, NULL, data);
+ setCallbackCommon(fd, POLL_CALLBACK, events, callback, NULL, data);
}
-void PollLoop::setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+void PollLoop::setLooperCallback(int fd, int ident, int events, ALooper_callbackFunc* callback,
void* data) {
- setCallbackCommon(fd, events, NULL, callback, data);
+ setCallbackCommon(fd, ident, events, NULL, callback, data);
}
-void PollLoop::setCallbackCommon(int fd, int events, Callback callback,
+void PollLoop::setCallbackCommon(int fd, int ident, int events, Callback callback,
ALooper_callbackFunc* looperCallback, void* data) {
#if DEBUG_CALLBACKS
@@ -305,6 +311,7 @@
RequestedCallback requestedCallback;
requestedCallback.callback = callback;
requestedCallback.looperCallback = looperCallback;
+ requestedCallback.ident = ident;
requestedCallback.data = data;
ssize_t index = getRequestIndexLocked(fd);
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 2b1f490..e5ece8e 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -21,6 +21,7 @@
#include <utils/Log.h>
#include <cutils/sched_policy.h>
+#include <cutils/properties.h>
#include <stdio.h>
#include <stdlib.h>
@@ -57,7 +58,7 @@
// ----------------------------------------------------------------------------
/*
- * Create and run a new thead.
+ * Create and run a new thread.
*
* We create it "detached", so it cleans up after itself.
*/
@@ -280,6 +281,22 @@
#endif
}
+#if defined(HAVE_PTHREADS)
+static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT;
+static bool gDoSchedulingGroup = true;
+
+static void checkDoSchedulingGroup(void) {
+ char buf[PROPERTY_VALUE_MAX];
+ int len = property_get("debug.sys.noschedgroups", buf, "");
+ if (len > 0) {
+ int temp;
+ if (sscanf(buf, "%d", &temp) == 1) {
+ gDoSchedulingGroup = temp == 0;
+ }
+ }
+}
+#endif
+
int androidSetThreadSchedulingGroup(pid_t tid, int grp)
{
if (grp > ANDROID_TGROUP_MAX || grp < 0) {
@@ -287,9 +304,12 @@
}
#if defined(HAVE_PTHREADS)
- if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
- SP_BACKGROUND : SP_FOREGROUND)) {
- return PERMISSION_DENIED;
+ pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
+ if (gDoSchedulingGroup) {
+ if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+ SP_BACKGROUND : SP_FOREGROUND)) {
+ return PERMISSION_DENIED;
+ }
}
#endif
@@ -303,10 +323,13 @@
#if defined(HAVE_PTHREADS)
int lasterr = 0;
- if (pri >= ANDROID_PRIORITY_BACKGROUND) {
- rc = set_sched_policy(tid, SP_BACKGROUND);
- } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
- rc = set_sched_policy(tid, SP_FOREGROUND);
+ pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
+ if (gDoSchedulingGroup) {
+ if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+ rc = set_sched_policy(tid, SP_BACKGROUND);
+ } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
+ rc = set_sched_policy(tid, SP_FOREGROUND);
+ }
}
if (rc) {
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index a0e01c6..2d53136 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -636,7 +636,7 @@
memcpy(buffer, ptr, uncompLen);
} else {
if (!inflateBuffer(buffer, ptr, uncompLen, compLen))
- goto unmap;
+ goto bail;
}
if (compLen > kSequentialMin)
@@ -644,8 +644,6 @@
result = true;
-unmap:
- file->release();
bail:
return result;
}
@@ -669,7 +667,7 @@
getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL);
- FileMap* file = createEntryFileMap(entry);
+ const FileMap* file = createEntryFileMap(entry);
if (file == NULL) {
goto bail;
}
@@ -680,23 +678,21 @@
ssize_t actual = write(fd, ptr, uncompLen);
if (actual < 0) {
LOGE("Write failed: %s\n", strerror(errno));
- goto unmap;
+ goto bail;
} else if ((size_t) actual != uncompLen) {
LOGE("Partial write during uncompress (%zd of %zd)\n",
(size_t)actual, (size_t)uncompLen);
- goto unmap;
+ goto bail;
} else {
LOGI("+++ successful write\n");
}
} else {
if (!inflateBuffer(fd, ptr, uncompLen, compLen))
- goto unmap;
+ goto bail;
}
result = true;
-unmap:
- file->release();
bail:
return result;
}
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 507fa5a..c204a94 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -106,7 +106,12 @@
void SoftwareRenderer::render(
const void *data, size_t size, void *platformPrivate) {
android_native_buffer_t *buf;
- CHECK_EQ(0, mSurface->dequeueBuffer(mSurface.get(), &buf));
+ int err;
+ if ((err = mSurface->dequeueBuffer(mSurface.get(), &buf)) != 0) {
+ LOGW("Surface::dequeueBuffer returned error %d", err);
+ return;
+ }
+
CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), buf));
GraphicBufferMapper &mapper = GraphicBufferMapper::get();
@@ -186,7 +191,9 @@
CHECK_EQ(0, mapper.unlock(buf->handle));
- CHECK_EQ(0, mSurface->queueBuffer(mSurface.get(), buf));
+ if ((err = mSurface->queueBuffer(mSurface.get(), buf)) != 0) {
+ LOGW("Surface::queueBuffer returned error %d", err);
+ }
buf = NULL;
}
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 379960a..c79f913 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -246,8 +246,8 @@
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
- ALooper_callbackFunc* callback, void* data) {
- queue->attachLooper(looper, callback, data);
+ int ident, ALooper_callbackFunc* callback, void* data) {
+ queue->attachLooper(looper, ident, callback, data);
}
void AInputQueue_detachLooper(AInputQueue* queue) {
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 1564c47..0aeed77 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -72,9 +72,9 @@
static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
}
-void ALooper_addFd(ALooper* looper, int fd, int events,
+void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
ALooper_callbackFunc* callback, void* data) {
- static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
+ static_cast<PollLoop*>(looper)->setLooperCallback(fd, ident, events, callback, data);
}
int32_t ALooper_removeFd(ALooper* looper, int fd) {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index db534e0..cf7635d 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -60,12 +60,12 @@
}
ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
- ALooper* looper, ALooper_callbackFunc* callback, void* data)
+ ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data)
{
sp<SensorEventQueue> queue =
static_cast<SensorManager*>(manager)->createEventQueue();
if (queue != 0) {
- ALooper_addFd(looper, queue->getFd(), POLLIN, callback, data);
+ ALooper_addFd(looper, queue->getFd(), ident, POLLIN, callback, data);
queue->looper = looper;
queue->incStrong(manager);
}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 418f609..5b62da4 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -623,10 +623,10 @@
/*
* Add this input queue to a looper for processing. See
- * ALooper_addFd() for information on the callback and data params.
+ * ALooper_addFd() for information on the ident, callback, and data params.
*/
void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
- ALooper_callbackFunc* callback, void* data);
+ int ident, ALooper_callbackFunc* callback, void* data);
/*
* Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 2917216..287bcd5 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -111,7 +111,7 @@
*
* Returns ALOPER_POLL_ERROR if an error occurred.
*
- * Returns a value >= 0 containing a file descriptor if it has data
+ * Returns a value >= 0 containing an identifier if its file descriptor has data
* and it has no callback function (requiring the caller here to handle it).
* In this (and only this) case outEvents and outData will contain the poll
* events and data associated with the fd.
@@ -145,10 +145,12 @@
* descriptor was previously added, it is replaced.
*
* "fd" is the file descriptor to be added.
+ * "ident" is an identifier for this event, which is returned from
+ * ALooper_pollOnce(). Must be >= 0, or ALOOPER_POLL_CALLBACK if
+ * providing a non-NULL callback.
* "events" are the poll events to wake up on. Typically this is POLLIN.
* "callback" is the function to call when there is an event on the file
* descriptor.
- * "id" is an identifier to associated with this file descriptor, or 0.
* "data" is a private data pointer to supply to the callback.
*
* There are two main uses of this function:
@@ -156,13 +158,13 @@
* (1) If "callback" is non-NULL, then
* this function will be called when there is data on the file descriptor. It
* should execute any events it has pending, appropriately reading from the
- * file descriptor.
+ * file descriptor. The 'ident' is ignored in this case.
*
- * (2) If "callback" is NULL, the fd will be returned by ALooper_pollOnce
- * when it has data available, requiring the caller to take care of processing
- * it.
+ * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce
+ * when its file descriptor has data available, requiring the caller to take
+ * care of processing it.
*/
-void ALooper_addFd(ALooper* looper, int fd, int events,
+void ALooper_addFd(ALooper* looper, int fd, int ident, int events,
ALooper_callbackFunc* callback, void* data);
/**
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
index b4ce024..a102d43 100644
--- a/native/include/android/sensor.h
+++ b/native/include/android/sensor.h
@@ -166,7 +166,7 @@
* Creates a new sensor event queue and associate it with a looper.
*/
ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager,
- ALooper* looper, ALooper_callbackFunc* callback, void* data);
+ ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data);
/*
* Destroys the event queue and free all resources associated to it.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
index 33acecb..48243ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -39,6 +39,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.Log;
import android.view.Display;
@@ -468,7 +469,11 @@
}
// Restart the ticker if it's still running
- tick(notification);
+ if (notification.notification.tickerText != null
+ && !TextUtils.equals(notification.notification.tickerText,
+ oldEntry.notification.notification.tickerText)) {
+ tick(notification);
+ }
// Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index e742887..5f26af4 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -175,8 +175,7 @@
}
public int getPhoneType() {
- // FIXME: add SIP phone type
- return Phone.PHONE_TYPE_GSM;
+ return Phone.PHONE_TYPE_SIP;
}
public SignalStrength getSignalStrength() {
diff --git a/test-runner/src/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java
index 64d11c5..2811b0d 100644
--- a/test-runner/src/android/test/ProviderTestCase2.java
+++ b/test-runner/src/android/test/ProviderTestCase2.java
@@ -74,7 +74,7 @@
private IsolatedContext mProviderContext;
private MockContentResolver mResolver;
- private class MockContext2 extends MockContext {
+ private class MockContext2 extends MockContext {
@Override
public Resources getResources() {
@@ -87,6 +87,11 @@
// one created through the regular Context
return getContext().getDir("mockcontext2_" + name, mode);
}
+
+ @Override
+ public Context getApplicationContext() {
+ return this;
+ }
}
/**
* Constructor.
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 34cbc44..db1e5ef 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -31,6 +31,16 @@
</activity>
<activity
+ android:name="ResizeActivity"
+ android:label="_Resize"
+ android:windowSoftInputMode="adjustResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="TextGammaActivity"
android:label="_Gamma"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
diff --git a/tests/HwAccelerationTest/res/layout/form.xml b/tests/HwAccelerationTest/res/layout/form.xml
new file mode 100644
index 0000000..0b17db1
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/form.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="First name" />
+
+ <EditText
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="3dip"
+ android:hint="Enter your first name" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Last name" />
+
+ <EditText
+ android:layout_width="0dip"
+ android:layout_weight="1.0"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="3dip"
+ android:hint="Enter your last name" />
+
+ </LinearLayout>
+
+ <EditText
+ android:layout_width="match_parent"
+ android:layout_weight="1.0"
+ android:layout_height="0dip"
+ android:background="#ff7f0000" />
+
+</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ResizeActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ResizeActivity.java
new file mode 100644
index 0000000..e5771b8
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ResizeActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.hwui;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ResizeActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.form);
+ }
+}