diff options
46 files changed, 395 insertions, 423 deletions
diff --git a/api/current.xml b/api/current.xml index 8ed7d93..b4fc949 100644 --- a/api/current.xml +++ b/api/current.xml @@ -15838,6 +15838,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" @@ -17059,50 +17103,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 @@ int delete_cache(const char *pkgname, int encrypted_fs_flag) /* 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 @@ static int disk_free() * 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 @@ int protect(char *pkgname, gid_t gid) 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 @@ static int stat_size(struct stat *s) 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 @@ static int calculate_dir_size(int dfd) 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 @@ int get_size(const char *pkgname, const char *apkpath, 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 @@ int get_size(const char *pkgname, const char *apkpath, } 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_rename(char **arg, char reply[REPLY_MAX]) 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_protect(char **arg, char reply[REPLY_MAX]) 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 move_dex(const char *src, const char *dst); 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 @@ package android.app; 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 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, // 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 class SharedPreferencesBackupHelper extends FileBackupHelperBase implemen 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 @@ public class SharedPreferencesBackupHelper extends FileBackupHelperBase implemen } } } - 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 class BatteryStats implements Parcelable { 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 class BatteryStats implements Parcelable { 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 class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { 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 @@ public abstract class BatteryStats implements Parcelable { 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/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,75 +132,76 @@ public class TimeUtils { 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; - } - if (duration > 0) { - builder.append("+"); - } else { - builder.append("-"); - 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) { - builder.append(days); - builder.append('d'); - doall = true; + 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 (doall || hours > 0) { - builder.append(hours); - builder.append('h'); - doall = true; + if (amt > 9 || (always && zeropad >= 2)) { + return 2+suffix; } - if (doall || minutes > 0) { - builder.append(minutes); - builder.append('m'); - doall = true; + if (always || amt > 0) { + return 1+suffix; } - if (doall || seconds > 0) { - builder.append(seconds); - builder.append('s'); - doall = true; + 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++; } - builder.append(millis); - builder.append("ms"); + return pos; } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long duration, PrintWriter pw) { + + private static int formatDurationLocked(long duration, int fieldLen) { + if (sFormatStr.length < fieldLen) { + sFormatStr = new char[fieldLen]; + } + + char[] formatStr = sFormatStr; + if (duration == 0) { - pw.print("0"); - return; + int pos = 0; + fieldLen -= 1; + while (pos < fieldLen) { + formatStr[pos] = ' '; + } + formatStr[pos] = '0'; + return pos+1; } + + char prefix; if (duration > 0) { - pw.print("+"); + prefix = '+'; } else { - pw.print("-"); + prefix = '-'; duration = -duration; } @@ -221,38 +222,62 @@ public class TimeUtils { 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; + 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 || seconds > 0) { - pw.print(seconds); - pw.print('s'); - 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); } - pw.print(millis); - pw.print("ms"); } + /** @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)); + } + } /** @hide Just for debugging; not internationalized. */ + public static void formatDuration(long duration, PrintWriter pw) { + 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/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java index 07c3e4b..4bbb540 100644 --- a/core/java/android/widget/QuickContactBadge.java +++ b/core/java/android/widget/QuickContactBadge.java @@ -236,6 +236,7 @@ public class QuickContactBadge extends ImageView implements OnClickListener { 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); @@ -249,12 +250,14 @@ public class QuickContactBadge extends ImageView implements OnClickListener { 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/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index f4447ab..566ed29 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -3343,11 +3343,6 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public class Pid { - long mWakeSum; - long mWakeStart; - } - /** * Retrieve the statistics object for a particular process, creating * if needed. @@ -3362,6 +3357,10 @@ public final class BatteryStatsImpl extends BatteryStats { return ps; } + public SparseArray<? extends Pid> getPidStats() { + return mPids; + } + public Pid getPidStatsLocked(int pid) { Pid p = mPids.get(pid); if (p == null) { @@ -3586,6 +3585,11 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override + public long getHistoryBaseTime() { + return mHistoryBaseTime; + } + + @Override public int getStartCount() { return mStartCount; } diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index 0932473..2517a8a 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -127,12 +127,13 @@ AInputQueue::~AInputQueue() { 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_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 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin 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-cs/strings.xml b/core/res/res/values-cs/strings.xml index 7942c56..55d9b6c 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Vybrat vše"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Označit text"</string> <string name="cut" msgid="3092569408438626261">"Vyjmout"</string> <string name="copy" msgid="2681946229533511987">"Kopírovat"</string> <string name="paste" msgid="5629880836805036433">"Vložit"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index bab18f2..9e6865e 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Vælg alle"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Marker tekst"</string> <string name="cut" msgid="3092569408438626261">"Klip"</string> <string name="copy" msgid="2681946229533511987">"Kopier"</string> <string name="paste" msgid="5629880836805036433">"Indsæt"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index c20aa16..1e1556f 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Alles auswählen"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Text auswählen"</string> <string name="cut" msgid="3092569408438626261">"Ausschneiden"</string> <string name="copy" msgid="2681946229533511987">"Kopieren"</string> <string name="paste" msgid="5629880836805036433">"Einfügen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index ab29601..a0bb65b 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Επιλογή όλων"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Επιλογή κειμένου"</string> <string name="cut" msgid="3092569408438626261">"Αποκοπή"</string> <string name="copy" msgid="2681946229533511987">"Αντιγραφή"</string> <string name="paste" msgid="5629880836805036433">"Επικόλληση"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index fce56cd..b07d79a 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar todos"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleccionar texto"</string> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Pegar"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 4fdaf3c..35e19a8 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar todo"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleccionar texto"</string> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Pegar"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 9f0fa0b..e826aba 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Tout sélectionner"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Sélectionner le texte"</string> <string name="cut" msgid="3092569408438626261">"Couper"</string> <string name="copy" msgid="2681946229533511987">"Copier"</string> <string name="paste" msgid="5629880836805036433">"Coller"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 4731f39..46b735e 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleziona tutto"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleziona testo"</string> <string name="cut" msgid="3092569408438626261">"Taglia"</string> <string name="copy" msgid="2681946229533511987">"Copia"</string> <string name="paste" msgid="5629880836805036433">"Incolla"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index a9613f4..802c6a3 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"すべて選択"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"テキストを選択"</string> <string name="cut" msgid="3092569408438626261">"切り取り"</string> <string name="copy" msgid="2681946229533511987">"コピー"</string> <string name="paste" msgid="5629880836805036433">"貼り付け"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index d6ab5ad..165c5e5 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"모두 선택"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"텍스트 선택"</string> <string name="cut" msgid="3092569408438626261">"잘라내기"</string> <string name="copy" msgid="2681946229533511987">"복사"</string> <string name="paste" msgid="5629880836805036433">"붙여넣기"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 021b20e..b4af7a6 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Merk alt"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Merk tekst"</string> <string name="cut" msgid="3092569408438626261">"Klipp ut"</string> <string name="copy" msgid="2681946229533511987">"Kopier"</string> <string name="paste" msgid="5629880836805036433">"Lim inn"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index a74db2b..8829f27 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Alles selecteren"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Tekst selecteren"</string> <string name="cut" msgid="3092569408438626261">"Knippen"</string> <string name="copy" msgid="2681946229533511987">"Kopiëren"</string> <string name="paste" msgid="5629880836805036433">"Plakken"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index f5ed50c..dd9747d 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Zaznacz wszystko"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Zaznacz tekst"</string> <string name="cut" msgid="3092569408438626261">"Wytnij"</string> <string name="copy" msgid="2681946229533511987">"Kopiuj"</string> <string name="paste" msgid="5629880836805036433">"Wklej"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 7914a3d..cce7ff9 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar tudo"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Seleccionar texto"</string> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Colar"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index c9c792e..7163fce 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Selecionar texto"</string> <string name="cut" msgid="3092569408438626261">"Recortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Colar"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 786571b..043e094 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Выбрать все"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Выбрать текст"</string> <string name="cut" msgid="3092569408438626261">"Вырезать"</string> <string name="copy" msgid="2681946229533511987">"Копировать"</string> <string name="paste" msgid="5629880836805036433">"Вставить"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 8a115697..e32746a 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Markera text"</string> <string name="cut" msgid="3092569408438626261">"Klipp ut"</string> <string name="copy" msgid="2681946229533511987">"Kopiera"</string> <string name="paste" msgid="5629880836805036433">"Klistra in"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index b45d5bb..bd87446 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Tümünü seç"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"Metin seç"</string> <string name="cut" msgid="3092569408438626261">"Kes"</string> <string name="copy" msgid="2681946229533511987">"Kopyala"</string> <string name="paste" msgid="5629880836805036433">"Yapıştır"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 88c38e5..aa1f93f 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"全选"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"选择文字"</string> <string name="cut" msgid="3092569408438626261">"剪切"</string> <string name="copy" msgid="2681946229533511987">"复制"</string> <string name="paste" msgid="5629880836805036433">"粘贴"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 7d3c27a..fdce813 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -703,8 +703,7 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"全部選取"</string> - <!-- no translation found for selectText (4862359311088898878) --> - <skip /> + <!-- outdated translation 3889149123626888637 --> <string name="selectText" msgid="4862359311088898878">"選取文字"</string> <string name="cut" msgid="3092569408438626261">"剪下"</string> <string name="copy" msgid="2681946229533511987">"複製"</string> <string name="paste" msgid="5629880836805036433">"貼上"</string> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index de419be..86e79c8 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1270,7 +1270,13 @@ <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/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 @@ outside the scope of this document.</p> <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> - -<blockquote> - -<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> - -<div style="padding-left:3em;padding-right:4em;"> - -<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 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>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. + +<p>(See <a href="#closing_notes">Closing Notes</a> for more on profiling and +writing effective benchmarks.) + +<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). + +<p>(If you need that kind of advice, see Josh Bloch's <em>Effective Java</em>, +item 47.)</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>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 @@ of its way to do the hard work for you, and even detect some cases where you're 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/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 @@ public: /* 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 @@ public: * 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 @@ private: 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 @@ private: 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 @@ sp<PollLoop> SensorEventQueue::getPollLoop() const 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/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 @@ void PollLoop::openWakePipe() { RequestedCallback requestedCallback; requestedCallback.callback = NULL; requestedCallback.looperCallback = NULL; + requestedCallback.ident = 0; requestedCallback.data = NULL; mRequestedCallbacks.insertAt(requestedCallback, 0); } @@ -116,7 +117,7 @@ int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) { 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 @@ int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) { 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 @@ int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) { 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 @@ bool PollLoop::getAllowNonCallbacks() const { 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 @@ void PollLoop::setCallbackCommon(int fd, int events, Callback callback, 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 @@ using namespace android; // ---------------------------------------------------------------------------- /* - * 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 @@ pid_t androidGetTid() #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 @@ int androidSetThreadSchedulingGroup(pid_t tid, int grp) } #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 @@ int androidSetThreadPriority(pid_t tid, int pri) #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/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 @@ float AMotionEvent_getHistoricalOrientation(AInputEvent* motion_event, size_t po 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 @@ void ALooper_release(ALooper* looper) { 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 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type } 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 @@ typedef struct AInputQueue AInputQueue; /* * 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 @@ enum { * * 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 @@ void ALooper_release(ALooper* looper); * 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 @@ void ALooper_release(ALooper* looper); * (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 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type * 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/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java index 8f2da7a..af736aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java @@ -46,6 +46,7 @@ import android.os.Handler; import android.os.Message; import android.os.ServiceManager; import android.os.SystemClock; +import android.text.TextUtils; import android.util.Slog; import android.util.Log; import android.view.Display; @@ -462,7 +463,11 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks } // 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(); |