diff options
-rw-r--r-- | carousel/test/res/values-in/strings.xml | 2 | ||||
-rw-r--r-- | chips/AndroidManifest.xml | 16 | ||||
-rw-r--r-- | chips/res/values-ko/strings.xml | 2 | ||||
-rw-r--r-- | chips/res/values-pt-rPT/strings.xml | 2 | ||||
-rw-r--r-- | chips/src/com/android/ex/chips/RecipientEditTextView.java | 108 | ||||
-rw-r--r-- | common/java/com/android/common/OperationScheduler.java | 53 | ||||
-rw-r--r-- | common/tests/src/com/android/common/OperationSchedulerTest.java | 40 | ||||
-rw-r--r-- | photoviewer/.gitignore | 8 | ||||
-rw-r--r-- | variablespeed/jni/Android.mk | 1 | ||||
-rw-r--r-- | variablespeed/jni/variablespeed.cc | 4 |
10 files changed, 167 insertions, 69 deletions
diff --git a/carousel/test/res/values-in/strings.xml b/carousel/test/res/values-in/strings.xml index 40000e8..06c8812 100644 --- a/carousel/test/res/values-in/strings.xml +++ b/carousel/test/res/values-in/strings.xml @@ -21,7 +21,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="music_demo_activity_label" msgid="4382090808250495841">"KaruselMusik"</string> <string name="carousel_test_activity_label" msgid="6014624482213318747">"UjiKarusel"</string> - <string name="carousel_test_activity_description" msgid="1632693812604375483">"Aplikasi untuk menampilkan penggunaan Karusel"</string> + <string name="carousel_test_activity_description" msgid="1632693812604375483">"Aplikasi untuk menampilkan penggunaan Korsel"</string> <string name="task_switcher_activity_label" msgid="714620143340933546">"PengubahTugas"</string> <string name="recent_tasks_title" msgid="1030287226205477117">"Aplikasi Terbaru"</string> <string name="no_recent_tasks" msgid="6884096266670555780">"Tidak ada tugas terbaru"</string> diff --git a/chips/AndroidManifest.xml b/chips/AndroidManifest.xml index e159fd2..fd7775d 100644 --- a/chips/AndroidManifest.xml +++ b/chips/AndroidManifest.xml @@ -1,5 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.ex.chips" android:versionCode="1"> -</manifest>
\ No newline at end of file +</manifest> diff --git a/chips/res/values-ko/strings.xml b/chips/res/values-ko/strings.xml index 7423ce5..f7884bd 100644 --- a/chips/res/values-ko/strings.xml +++ b/chips/res/values-ko/strings.xml @@ -19,5 +19,5 @@ <string name="more_string" msgid="8495478259330621990">"<xliff:g id="COUNT">%1$s</xliff:g>명 이상"</string> <string name="copy_email" msgid="7869435992461603532">"이메일 주소 복사"</string> <string name="copy_number" msgid="530057841276106843">"전화번호 복사"</string> - <string name="done" msgid="2356320650733788862">"Enter 키"</string> + <string name="done" msgid="2356320650733788862">"입력"</string> </resources> diff --git a/chips/res/values-pt-rPT/strings.xml b/chips/res/values-pt-rPT/strings.xml index bfbe1ca..fc991b1 100644 --- a/chips/res/values-pt-rPT/strings.xml +++ b/chips/res/values-pt-rPT/strings.xml @@ -19,5 +19,5 @@ <string name="more_string" msgid="8495478259330621990">"+<xliff:g id="COUNT">%1$s</xliff:g>"</string> <string name="copy_email" msgid="7869435992461603532">"Copiar endereço de email"</string> <string name="copy_number" msgid="530057841276106843">"Copiar número de telefone"</string> - <string name="done" msgid="2356320650733788862">"Regressar"</string> + <string name="done" msgid="2356320650733788862">"Voltar"</string> </resources> diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java index 41bab18..8b6367f 100644 --- a/chips/src/com/android/ex/chips/RecipientEditTextView.java +++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java @@ -57,6 +57,7 @@ import android.text.InputType; import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; @@ -409,6 +410,44 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } } + private int getExcessTopPadding() { + if (sExcessTopPadding == -1) { + sExcessTopPadding = (int) (mChipHeight + mLineSpacingExtra); + } + return sExcessTopPadding; + } + + public <T extends ListAdapter & Filterable> void setAdapter(T adapter) { + super.setAdapter(adapter); + ((BaseRecipientAdapter) adapter) + .registerUpdateObserver(new BaseRecipientAdapter.EntriesUpdatedObserver() { + @Override + public void onChanged(List<RecipientEntry> entries) { + // Scroll the chips field to the top of the screen so + // that the user can see as many results as possible. + if (entries != null && entries.size() > 0) { + scrollBottomIntoView(); + } + } + }); + } + + private void scrollBottomIntoView() { + if (mScrollView != null && mShouldShrink) { + int[] location = new int[2]; + getLocationOnScreen(location); + int height = getHeight(); + int currentPos = location[1] + height; + // Desired position shows at least 1 line of chips below the action + // bar. We add excess padding to make sure this is always below other + // content. + int desiredPos = (int) mChipHeight + mActionBarHeight + getExcessTopPadding(); + if (currentPos > desiredPos) { + mScrollView.scrollBy(0, currentPos - desiredPos); + } + } + } + @Override public void performValidation() { // Do nothing. Chips handles its own validation. @@ -921,7 +960,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements String token = editable.toString().substring(tokenStart, tokenEnd); final String trimmedToken = token.trim(); int commitCharIndex = trimmedToken.lastIndexOf(COMMIT_CHAR_COMMA); - if (commitCharIndex == trimmedToken.length() - 1) { + if (commitCharIndex != -1 && commitCharIndex == trimmedToken.length() - 1) { token = trimmedToken.substring(0, trimmedToken.length() - 1); } RecipientEntry entry = createTokenizedEntry(token); @@ -1600,6 +1639,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + if (position < 0) { + return; + } submitItemAtPosition(position); } @@ -2249,45 +2291,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } } - @Override - public <T extends ListAdapter & Filterable> void setAdapter(T adapter) { - super.setAdapter(adapter); - ((BaseRecipientAdapter) adapter) - .registerUpdateObserver(new BaseRecipientAdapter.EntriesUpdatedObserver() { - @Override - public void onChanged(List<RecipientEntry> entries) { - if (entries != null && entries.size() > 0) { - scrollBottomIntoView(); - } - } - }); - } - - private void scrollBottomIntoView() { - if (mScrollView != null && mShouldShrink) { - int[] location = new int[2]; - getLocationOnScreen(location); - int height = getHeight(); - int currentPos = location[1] + height; - // Desired position shows at least 1 line of chips below the action - // bar. - // We add excess padding to make sure this is always below other - // content. - int desiredPos = (int) mChipHeight + mActionBarHeight + getExcessTopPadding(); - if (currentPos > desiredPos) { - mScrollView.scrollBy(0, currentPos - desiredPos); - } - } - } - - private int getExcessTopPadding() { - if (sExcessTopPadding == -1) { - sExcessTopPadding = (int) (mChipHeight + mLineSpacingExtra); - } - return sExcessTopPadding; - } - - public boolean lastCharacterIsCommitCharacter(CharSequence s) { + public boolean lastCharacterIsCommitCharacter(CharSequence s) { char last; int end = getSelectionEnd() == 0 ? 0 : getSelectionEnd() - 1; int len = length() - 1; @@ -2366,6 +2370,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements prevTokenStart = tokenStart; tokenStart = mTokenizer.findTokenStart(text, tokenStart); findChip = findChip(tokenStart); + if (tokenStart == originalTokenStart && findChip == null) { + break; + } } if (tokenStart != originalTokenStart) { if (findChip != null) { @@ -2542,11 +2549,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements final Runnable runnable = new Runnable() { @Override public void run() { - Editable oldText = getText(); - int start, end; + final Editable text = new SpannableStringBuilder(getText()); int i = 0; - for (DrawableRecipientChip chip : recipients) { - DrawableRecipientChip replacement = replacements.get(i); + for (final DrawableRecipientChip chip : recipients) { + final DrawableRecipientChip replacement = replacements.get(i); if (replacement != null) { final RecipientEntry oldEntry = chip.getEntry(); final RecipientEntry newEntry = replacement.getEntry(); @@ -2556,25 +2562,24 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements if (isBetter) { // Find the location of the chip in the text currently shown. - start = oldText.getSpanStart(chip); + final int start = text.getSpanStart(chip); if (start != -1) { // Replacing the entirety of what the chip represented, // including the extra space dividing it from other chips. - end = oldText.getSpanEnd(chip) + 1; - oldText.removeSpan(chip); + final int end = text.getSpanEnd(chip) + 1; + text.removeSpan(chip); // Make sure we always have just 1 space at the end to // separate this chip from the next chip. - SpannableString displayText = + final SpannableString displayText = new SpannableString(createAddressText( - replacement.getEntry()).trim() - + " "); + replacement.getEntry()).trim() + " "); displayText.setSpan(replacement, 0, displayText.length() - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // Replace the old text we found with with the new display // text, which now may also contain the display name of the // recipient. - oldText.replace(start, end, displayText); + text.replace(start, end, displayText); replacement.setOriginalText(displayText.toString()); replacements.set(i, null); @@ -2584,6 +2589,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements } i++; } + setText(text); } }; diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java index b8fc7bc..261b15d 100644 --- a/common/java/com/android/common/OperationScheduler.java +++ b/common/java/com/android/common/OperationScheduler.java @@ -42,6 +42,9 @@ public class OperationScheduler { /** Wait this long times the number of consecutive errors so far before retrying. */ public long backoffIncrementalMillis = 5000; + /** Wait this long times 2^(number of consecutive errors so far) before retrying. */ + public int backoffExponentialMillis = 0; + /** Maximum duration of moratorium to honor. Mostly an issue for clock rollbacks. */ public long maxMoratoriumMillis = 24 * 3600 * 1000; @@ -53,11 +56,20 @@ public class OperationScheduler { @Override public String toString() { - return String.format( + if (backoffExponentialMillis > 0) { + return String.format( + "OperationScheduler.Options[backoff=%.1f+%.1f+%.1f max=%.1f min=%.1f period=%.1f]", + backoffFixedMillis / 1000.0, backoffIncrementalMillis / 1000.0, + backoffExponentialMillis / 1000.0, + maxMoratoriumMillis / 1000.0, minTriggerMillis / 1000.0, + periodicIntervalMillis / 1000.0); + } else { + return String.format( "OperationScheduler.Options[backoff=%.1f+%.1f max=%.1f min=%.1f period=%.1f]", backoffFixedMillis / 1000.0, backoffIncrementalMillis / 1000.0, maxMoratoriumMillis / 1000.0, minTriggerMillis / 1000.0, periodicIntervalMillis / 1000.0); + } } } @@ -76,7 +88,7 @@ public class OperationScheduler { * Parse scheduler options supplied in this string form: * * <pre> - * backoff=(fixed)+(incremental) max=(maxmoratorium) min=(mintrigger) [period=](interval) + * backoff=(fixed)+(incremental)[+(exponential)] max=(maxmoratorium) min=(mintrigger) [period=](interval) * </pre> * * All values are times in (possibly fractional) <em>seconds</em> (not milliseconds). @@ -97,14 +109,18 @@ public class OperationScheduler { for (String param : spec.split(" +")) { if (param.length() == 0) continue; if (param.startsWith("backoff=")) { - int plus = param.indexOf('+', 8); - if (plus < 0) { - options.backoffFixedMillis = parseSeconds(param.substring(8)); - } else { - if (plus > 8) { - options.backoffFixedMillis = parseSeconds(param.substring(8, plus)); - } - options.backoffIncrementalMillis = parseSeconds(param.substring(plus + 1)); + String[] pieces = param.substring(8).split("\\+"); + if (pieces.length > 3) { + throw new IllegalArgumentException("bad value for backoff: [" + spec + "]"); + } + if (pieces.length > 0 && pieces[0].length() > 0) { + options.backoffFixedMillis = parseSeconds(pieces[0]); + } + if (pieces.length > 1 && pieces[1].length() > 0) { + options.backoffIncrementalMillis = parseSeconds(pieces[1]); + } + if (pieces.length > 2 && pieces[2].length() > 0) { + options.backoffExponentialMillis = (int)parseSeconds(pieces[2]); } } else if (param.startsWith("max=")) { options.maxMoratoriumMillis = parseSeconds(param.substring(4)); @@ -160,8 +176,21 @@ public class OperationScheduler { time = Math.max(time, moratoriumTimeMillis); time = Math.max(time, lastSuccessTimeMillis + options.minTriggerMillis); if (errorCount > 0) { - time = Math.max(time, lastErrorTimeMillis + options.backoffFixedMillis + - options.backoffIncrementalMillis * errorCount); + int shift = errorCount-1; + // backoffExponentialMillis is an int, so we can safely + // double it 30 times without overflowing a long. + if (shift > 30) shift = 30; + long backoff = options.backoffFixedMillis + + (options.backoffIncrementalMillis * errorCount) + + (((long)options.backoffExponentialMillis) << shift); + + // Treat backoff like a moratorium: don't let the backoff + // time grow too large. + if (moratoriumTimeMillis > 0 && backoff > moratoriumTimeMillis) { + backoff = moratoriumTimeMillis; + } + + time = Math.max(time, lastErrorTimeMillis + backoff); } return time; } diff --git a/common/tests/src/com/android/common/OperationSchedulerTest.java b/common/tests/src/com/android/common/OperationSchedulerTest.java index 955508f..87e2cd8 100644 --- a/common/tests/src/com/android/common/OperationSchedulerTest.java +++ b/common/tests/src/com/android/common/OperationSchedulerTest.java @@ -119,6 +119,42 @@ public class OperationSchedulerTest extends AndroidTestCase { assertEquals(beforeSuccess + 1000000, scheduler.getNextTimeMillis(options)); } + @MediumTest + public void testExponentialBackoff() throws Exception { + TimeTravelScheduler scheduler = new TimeTravelScheduler(); + OperationScheduler.Options options = new OperationScheduler.Options(); + options.backoffFixedMillis = 100; + options.backoffIncrementalMillis = 1000; + options.backoffExponentialMillis = 10000; + scheduler.setTriggerTimeMillis(0); + scheduler.setEnabledState(true); + + // Backoff interval after an error + long beforeError = (scheduler.timeMillis += 10); + scheduler.onTransientError(); + assertEquals(0, scheduler.getLastSuccessTimeMillis()); + assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); + assertEquals(beforeError + 11100, scheduler.getNextTimeMillis(options)); + + // Second error + beforeError = (scheduler.timeMillis += 10); + scheduler.onTransientError(); + assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); + assertEquals(beforeError + 22100, scheduler.getNextTimeMillis(options)); + + // Third error + beforeError = (scheduler.timeMillis += 10); + scheduler.onTransientError(); + assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); + assertEquals(beforeError + 43100, scheduler.getNextTimeMillis(options)); + + // Fourth error + beforeError = (scheduler.timeMillis += 10); + scheduler.onTransientError(); + assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); + assertEquals(beforeError + 84100, scheduler.getNextTimeMillis(options)); + } + @SmallTest public void testParseOptions() throws Exception { OperationScheduler.Options options = new OperationScheduler.Options(); @@ -138,6 +174,10 @@ public class OperationSchedulerTest extends AndroidTestCase { assertEquals( "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]", OperationScheduler.parseOptions("", options).toString()); + + assertEquals( + "OperationScheduler.Options[backoff=5.0+2.5+10.0 max=12345.6 min=7.0 period=3600.0]", + OperationScheduler.parseOptions("backoff=5.0++10.0 3600", options).toString()); } @SmallTest diff --git a/photoviewer/.gitignore b/photoviewer/.gitignore new file mode 100644 index 0000000..ff7ef7d --- /dev/null +++ b/photoviewer/.gitignore @@ -0,0 +1,8 @@ +*~ +*.bak +*.class +bin/ +gen/ +*.properties +.classpath +.project diff --git a/variablespeed/jni/Android.mk b/variablespeed/jni/Android.mk index 66ec1c5..08de535 100644 --- a/variablespeed/jni/Android.mk +++ b/variablespeed/jni/Android.mk @@ -44,6 +44,7 @@ LOCAL_SHARED_LIBRARIES := \ libstlport \ libutils \ libcutils \ + liblog \ LOCAL_LDLIBS := \ -lOpenSLES \ diff --git a/variablespeed/jni/variablespeed.cc b/variablespeed/jni/variablespeed.cc index ea134ec..73ac609 100644 --- a/variablespeed/jni/variablespeed.cc +++ b/variablespeed/jni/variablespeed.cc @@ -582,7 +582,7 @@ static void CreateAndRealizeAudioPlayer(SLuint32 slSampleRate, const size_t playerInterfaceCount = 2; const SLInterfaceID iids[playerInterfaceCount] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean reqs[playerInterfaceCount] = { SL_BOOLEAN_TRUE }; + const SLboolean reqs[playerInterfaceCount] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; OpenSL(engineInterface, CreateAudioPlayer, &audioPlayer, &playingSrc, &audioSnk, playerInterfaceCount, iids, reqs); setAudioStreamType(audioPlayer, audioStreamType); @@ -619,7 +619,7 @@ bool AudioEngine::PlayFromThisSource(const SLDataSource& audioSrc) { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_PREFETCHSTATUS, SL_IID_SEEK, SL_IID_METADATAEXTRACTION, SL_IID_ANDROIDCONFIGURATION }; const SLboolean decodePlayerRequired[decoderInterfaceCount] = { - SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; + SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; SLDataSource sourceCopy(audioSrc); OpenSL(engineInterface, CreateAudioPlayer, &decoder, &sourceCopy, &decDest, decoderInterfaceCount, decodePlayerInterfaces, decodePlayerRequired); |