summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Cerqueira <cyanogenmod@cerqueira.org>2013-07-24 22:53:16 +0100
committerRicardo Cerqueira <cyanogenmod@cerqueira.org>2013-07-24 22:53:16 +0100
commit5ae14b02bacf85e848eb6aa507a38c8f18c2f595 (patch)
tree0087a8f58db5256b85716cb434b465c1f2da40d8
parentaff1242e5451db7edf4fc165895b656dea722593 (diff)
parentf881a0565252fe947775d499768ef6a46490348a (diff)
downloadandroid_frameworks_ex-5ae14b02bacf85e848eb6aa507a38c8f18c2f595.tar.gz
android_frameworks_ex-5ae14b02bacf85e848eb6aa507a38c8f18c2f595.tar.bz2
android_frameworks_ex-5ae14b02bacf85e848eb6aa507a38c8f18c2f595.zip
Merge tag 'android-4.3_r2.1' into cm-10.2
Android 4.3 release 2.1
-rw-r--r--carousel/test/res/values-in/strings.xml2
-rw-r--r--chips/Android.mk7
-rw-r--r--chips/res/drawable-hdpi/ic_contact_picture.pngbin5929 -> 944 bytes
-rw-r--r--chips/res/drawable-mdpi/ic_contact_picture.pngbin4733 -> 686 bytes
-rw-r--r--chips/res/drawable-xhdpi/ic_contact_picture.pngbin7422 -> 1299 bytes
-rw-r--r--chips/res/values-ko/strings.xml2
-rw-r--r--chips/res/values-pt-rPT/strings.xml2
-rw-r--r--chips/res/values/dimen.xml1
-rw-r--r--chips/src/com/android/ex/chips/BaseRecipientAdapter.java56
-rw-r--r--chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java256
-rw-r--r--chips/src/com/android/ex/chips/RecipientEditTextView.java793
-rw-r--r--chips/src/com/android/ex/chips/RecipientEntry.java118
-rw-r--r--chips/src/com/android/ex/chips/SingleRecipientArrayAdapter.java4
-rw-r--r--chips/src/com/android/ex/chips/recipientchip/BaseRecipientChip.java73
-rw-r--r--chips/src/com/android/ex/chips/recipientchip/DrawableRecipientChip.java36
-rw-r--r--chips/src/com/android/ex/chips/recipientchip/InvisibleRecipientChip.java105
-rw-r--r--chips/src/com/android/ex/chips/recipientchip/SimpleRecipientChip.java (renamed from chips/src/com/android/ex/chips/RecipientChip.java)69
-rw-r--r--chips/src/com/android/ex/chips/recipientchip/VisibleRecipientChip.java99
-rw-r--r--chips/tests/Android.mk1
-rw-r--r--chips/tests/src/com/android/ex/chips/ChipsTest.java174
-rw-r--r--chips/tests/src/com/android/ex/chips/RecipientAlternatesAdapterTest.java56
-rw-r--r--common/java/com/android/common/OperationScheduler.java53
-rw-r--r--common/tests/src/com/android/common/OperationSchedulerTest.java40
-rw-r--r--photoviewer/.gitignore8
-rw-r--r--photoviewer/Android.mk32
-rw-r--r--photoviewer/AndroidManifest.xml21
-rw-r--r--photoviewer/res/drawable-hdpi/actionbar_translucent.9.pngbin155 -> 0 bytes
-rw-r--r--photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.pngbin1330 -> 0 bytes
-rw-r--r--photoviewer/res/drawable-mdpi/actionbar_translucent.9.pngbin153 -> 0 bytes
-rw-r--r--photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.pngbin889 -> 0 bytes
-rw-r--r--photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.pngbin1765 -> 0 bytes
-rw-r--r--photoviewer/res/drawable/default_image.pngbin504 -> 0 bytes
-rw-r--r--photoviewer/res/layout/photo_activity_view.xml28
-rw-r--r--photoviewer/res/layout/photo_fragment_view.xml82
-rw-r--r--photoviewer/res/values-af/strings.xml23
-rw-r--r--photoviewer/res/values-am/strings.xml23
-rw-r--r--photoviewer/res/values-ar/strings.xml23
-rw-r--r--photoviewer/res/values-be/strings.xml23
-rw-r--r--photoviewer/res/values-bg/strings.xml23
-rw-r--r--photoviewer/res/values-ca/strings.xml23
-rw-r--r--photoviewer/res/values-cs/strings.xml23
-rw-r--r--photoviewer/res/values-da/strings.xml23
-rw-r--r--photoviewer/res/values-de/strings.xml23
-rw-r--r--photoviewer/res/values-el/strings.xml23
-rw-r--r--photoviewer/res/values-en-rGB/strings.xml23
-rw-r--r--photoviewer/res/values-es-rUS/strings.xml23
-rw-r--r--photoviewer/res/values-es/strings.xml23
-rw-r--r--photoviewer/res/values-et/strings.xml23
-rw-r--r--photoviewer/res/values-fa/strings.xml23
-rw-r--r--photoviewer/res/values-fi/strings.xml23
-rw-r--r--photoviewer/res/values-fr/strings.xml23
-rw-r--r--photoviewer/res/values-hi/strings.xml23
-rw-r--r--photoviewer/res/values-hr/strings.xml23
-rw-r--r--photoviewer/res/values-hu/strings.xml23
-rw-r--r--photoviewer/res/values-in/strings.xml23
-rw-r--r--photoviewer/res/values-it/strings.xml23
-rw-r--r--photoviewer/res/values-iw/strings.xml23
-rw-r--r--photoviewer/res/values-ja/strings.xml23
-rw-r--r--photoviewer/res/values-ko/strings.xml23
-rw-r--r--photoviewer/res/values-lt/strings.xml23
-rw-r--r--photoviewer/res/values-lv/strings.xml23
-rw-r--r--photoviewer/res/values-ms/strings.xml23
-rw-r--r--photoviewer/res/values-nb/strings.xml23
-rw-r--r--photoviewer/res/values-nl/strings.xml23
-rw-r--r--photoviewer/res/values-pl/strings.xml23
-rw-r--r--photoviewer/res/values-pt-rPT/strings.xml23
-rw-r--r--photoviewer/res/values-pt/strings.xml23
-rw-r--r--photoviewer/res/values-ro/strings.xml23
-rw-r--r--photoviewer/res/values-ru/strings.xml23
-rw-r--r--photoviewer/res/values-sk/strings.xml23
-rw-r--r--photoviewer/res/values-sl/strings.xml23
-rw-r--r--photoviewer/res/values-sr/strings.xml23
-rw-r--r--photoviewer/res/values-sv/strings.xml23
-rw-r--r--photoviewer/res/values-sw/strings.xml23
-rw-r--r--photoviewer/res/values-th/strings.xml23
-rw-r--r--photoviewer/res/values-tl/strings.xml23
-rw-r--r--photoviewer/res/values-tr/strings.xml23
-rw-r--r--photoviewer/res/values-uk/strings.xml23
-rw-r--r--photoviewer/res/values-vi/strings.xml23
-rw-r--r--photoviewer/res/values-zh-rCN/strings.xml23
-rw-r--r--photoviewer/res/values-zh-rTW/strings.xml23
-rw-r--r--photoviewer/res/values-zu/strings.xml23
-rw-r--r--photoviewer/res/values/colors.xml23
-rw-r--r--photoviewer/res/values/constants.xml21
-rw-r--r--photoviewer/res/values/dimen.xml25
-rw-r--r--photoviewer/res/values/strings.xml22
-rw-r--r--photoviewer/res/values/themes.xml30
-rw-r--r--photoviewer/sample/Android.mk47
-rw-r--r--photoviewer/sample/AndroidManifest.xml35
-rw-r--r--photoviewer/sample/assets/blah.pngbin550644 -> 0 bytes
-rw-r--r--photoviewer/sample/assets/galaxy.pngbin762095 -> 0 bytes
-rw-r--r--photoviewer/sample/assets/johannson.pngbin460793 -> 0 bytes
-rw-r--r--photoviewer/sample/assets/planets.pngbin178597 -> 0 bytes
-rw-r--r--photoviewer/sample/res/drawable-hdpi/ic_action_search.pngbin3120 -> 0 bytes
-rw-r--r--photoviewer/sample/res/drawable-hdpi/ic_launcher.pngbin4996 -> 0 bytes
-rw-r--r--photoviewer/sample/res/drawable-mdpi/ic_action_search.pngbin3030 -> 0 bytes
-rw-r--r--photoviewer/sample/res/drawable-mdpi/ic_launcher.pngbin3065 -> 0 bytes
-rw-r--r--photoviewer/sample/res/drawable-xhdpi/ic_action_search.pngbin3199 -> 0 bytes
-rw-r--r--photoviewer/sample/res/drawable-xhdpi/ic_launcher.pngbin6679 -> 0 bytes
-rw-r--r--photoviewer/sample/res/layout/activity_main.xml16
-rw-r--r--photoviewer/sample/res/menu/activity_main.xml6
-rw-r--r--photoviewer/sample/res/values-af/strings.xml8
-rw-r--r--photoviewer/sample/res/values-am/strings.xml8
-rw-r--r--photoviewer/sample/res/values-ar/strings.xml8
-rw-r--r--photoviewer/sample/res/values-be/strings.xml8
-rw-r--r--photoviewer/sample/res/values-bg/strings.xml8
-rw-r--r--photoviewer/sample/res/values-ca/strings.xml8
-rw-r--r--photoviewer/sample/res/values-cs/strings.xml8
-rw-r--r--photoviewer/sample/res/values-da/strings.xml8
-rw-r--r--photoviewer/sample/res/values-de/strings.xml8
-rw-r--r--photoviewer/sample/res/values-el/strings.xml8
-rw-r--r--photoviewer/sample/res/values-en-rGB/strings.xml8
-rw-r--r--photoviewer/sample/res/values-es-rUS/strings.xml8
-rw-r--r--photoviewer/sample/res/values-es/strings.xml8
-rw-r--r--photoviewer/sample/res/values-et/strings.xml8
-rw-r--r--photoviewer/sample/res/values-fa/strings.xml8
-rw-r--r--photoviewer/sample/res/values-fi/strings.xml8
-rw-r--r--photoviewer/sample/res/values-fr/strings.xml8
-rw-r--r--photoviewer/sample/res/values-hi/strings.xml8
-rw-r--r--photoviewer/sample/res/values-hr/strings.xml8
-rw-r--r--photoviewer/sample/res/values-hu/strings.xml8
-rw-r--r--photoviewer/sample/res/values-in/strings.xml8
-rw-r--r--photoviewer/sample/res/values-it/strings.xml8
-rw-r--r--photoviewer/sample/res/values-iw/strings.xml8
-rw-r--r--photoviewer/sample/res/values-ja/strings.xml8
-rw-r--r--photoviewer/sample/res/values-ko/strings.xml8
-rw-r--r--photoviewer/sample/res/values-lt/strings.xml8
-rw-r--r--photoviewer/sample/res/values-lv/strings.xml8
-rw-r--r--photoviewer/sample/res/values-ms/strings.xml8
-rw-r--r--photoviewer/sample/res/values-nb/strings.xml8
-rw-r--r--photoviewer/sample/res/values-nl/strings.xml8
-rw-r--r--photoviewer/sample/res/values-pl/strings.xml8
-rw-r--r--photoviewer/sample/res/values-pt-rPT/strings.xml8
-rw-r--r--photoviewer/sample/res/values-pt/strings.xml8
-rw-r--r--photoviewer/sample/res/values-ro/strings.xml8
-rw-r--r--photoviewer/sample/res/values-ru/strings.xml8
-rw-r--r--photoviewer/sample/res/values-sk/strings.xml8
-rw-r--r--photoviewer/sample/res/values-sl/strings.xml8
-rw-r--r--photoviewer/sample/res/values-sr/strings.xml8
-rw-r--r--photoviewer/sample/res/values-sv/strings.xml8
-rw-r--r--photoviewer/sample/res/values-sw/strings.xml8
-rw-r--r--photoviewer/sample/res/values-th/strings.xml8
-rw-r--r--photoviewer/sample/res/values-tl/strings.xml8
-rw-r--r--photoviewer/sample/res/values-tr/strings.xml8
-rw-r--r--photoviewer/sample/res/values-uk/strings.xml8
-rw-r--r--photoviewer/sample/res/values-vi/strings.xml8
-rw-r--r--photoviewer/sample/res/values-zh-rCN/strings.xml8
-rw-r--r--photoviewer/sample/res/values-zh-rTW/strings.xml8
-rw-r--r--photoviewer/sample/res/values-zu/strings.xml8
-rw-r--r--photoviewer/sample/res/values/dimens.xml7
-rw-r--r--photoviewer/sample/res/values/strings.xml8
-rw-r--r--photoviewer/sample/res/values/styles.xml5
-rw-r--r--photoviewer/sample/src/com/example/photoviewersample/MainActivity.java30
-rw-r--r--photoviewer/sample/src/com/example/photoviewersample/SampleProvider.java179
-rw-r--r--photoviewer/src/com/android/ex/photo/Intents.java148
-rw-r--r--photoviewer/src/com/android/ex/photo/PhotoViewActivity.java540
-rw-r--r--photoviewer/src/com/android/ex/photo/PhotoViewPager.java188
-rw-r--r--photoviewer/src/com/android/ex/photo/adapters/BaseCursorPagerAdapter.java261
-rw-r--r--photoviewer/src/com/android/ex/photo/adapters/BaseFragmentPagerAdapter.java188
-rw-r--r--photoviewer/src/com/android/ex/photo/adapters/PhotoPagerAdapter.java74
-rw-r--r--photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java444
-rw-r--r--photoviewer/src/com/android/ex/photo/loaders/PhotoBitmapLoader.java160
-rw-r--r--photoviewer/src/com/android/ex/photo/loaders/PhotoPagerLoader.java53
-rw-r--r--photoviewer/src/com/android/ex/photo/provider/PhotoContract.java74
-rw-r--r--photoviewer/src/com/android/ex/photo/util/Exif.java137
-rw-r--r--photoviewer/src/com/android/ex/photo/util/ImageUtils.java211
-rw-r--r--photoviewer/src/com/android/ex/photo/views/PhotoView.java1288
-rw-r--r--photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java68
-rw-r--r--variablespeed/jni/Android.mk1
169 files changed, 1411 insertions, 6484 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/Android.mk b/chips/Android.mk
index 4a7977a..6aa8a01 100644
--- a/chips/Android.mk
+++ b/chips/Android.mk
@@ -21,4 +21,9 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-logtags-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-include $(BUILD_STATIC_JAVA_LIBRARY) \ No newline at end of file
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+##################################################
+# Build all sub-directories
+
+include $(call all-makefiles-under,$(LOCAL_PATH)) \ No newline at end of file
diff --git a/chips/res/drawable-hdpi/ic_contact_picture.png b/chips/res/drawable-hdpi/ic_contact_picture.png
index 2eef7b5..4c0e35e 100644
--- a/chips/res/drawable-hdpi/ic_contact_picture.png
+++ b/chips/res/drawable-hdpi/ic_contact_picture.png
Binary files differ
diff --git a/chips/res/drawable-mdpi/ic_contact_picture.png b/chips/res/drawable-mdpi/ic_contact_picture.png
index 6c7cb61..ead9718 100644
--- a/chips/res/drawable-mdpi/ic_contact_picture.png
+++ b/chips/res/drawable-mdpi/ic_contact_picture.png
Binary files differ
diff --git a/chips/res/drawable-xhdpi/ic_contact_picture.png b/chips/res/drawable-xhdpi/ic_contact_picture.png
index 1a2bfde..05a65f6 100644
--- a/chips/res/drawable-xhdpi/ic_contact_picture.png
+++ b/chips/res/drawable-xhdpi/ic_contact_picture.png
Binary files differ
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/res/values/dimen.xml b/chips/res/values/dimen.xml
index b93555f..98354d2 100644
--- a/chips/res/values/dimen.xml
+++ b/chips/res/values/dimen.xml
@@ -19,4 +19,5 @@
<dimen name="chip_height">32dip</dimen>
<dimen name="chip_text_size">14sp</dimen>
<dimen name="line_spacing_extra">4dip</dimen>
+ <integer name="chips_max_lines">-1</integer>
</resources> \ No newline at end of file
diff --git a/chips/src/com/android/ex/chips/BaseRecipientAdapter.java b/chips/src/com/android/ex/chips/BaseRecipientAdapter.java
index c981728..71b610e 100644
--- a/chips/src/com/android/ex/chips/BaseRecipientAdapter.java
+++ b/chips/src/com/android/ex/chips/BaseRecipientAdapter.java
@@ -73,12 +73,12 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
* The number of extra entries requested to allow for duplicates. Duplicates
* are removed from the overall result.
*/
- private static final int ALLOWANCE_FOR_DUPLICATES = 5;
+ static final int ALLOWANCE_FOR_DUPLICATES = 5;
// This is ContactsContract.PRIMARY_ACCOUNT_NAME. Available from ICS as hidden
- private static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
+ static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
// This is ContactsContract.PRIMARY_ACCOUNT_TYPE. Available from ICS as hidden
- private static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
+ static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
/** The number of photos cached in this Adapter. */
private static final int PHOTO_CACHE_SIZE = 20;
@@ -118,7 +118,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
public static final int PHOTO = 0;
}
- private static class DirectoryListQuery {
+ protected static class DirectoryListQuery {
public static final Uri URI =
Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories");
@@ -234,8 +234,8 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
}
// We'll copy this result to mEntry in publicResults() (run in the UX thread).
- final List<RecipientEntry> entries = constructEntryList(false,
- entryMap, nonAggregatedEntries, existingDestinations);
+ final List<RecipientEntry> entries = constructEntryList(
+ entryMap, nonAggregatedEntries);
// After having local results, check the size of results. If the results are
// not enough, we search remote directories, which will take longer time.
@@ -250,7 +250,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
directoryCursor = mContentResolver.query(
DirectoryListQuery.URI, DirectoryListQuery.PROJECTION,
null, null, null);
- paramsList = setupOtherDirectories(directoryCursor);
+ paramsList = setupOtherDirectories(mContext, directoryCursor, mAccount);
} else {
// We don't need to search other directories.
paramsList = null;
@@ -424,8 +424,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
}
// Show the list again without "waiting" message.
- updateEntries(constructEntryList(false,
- mEntryMap, mNonAggregatedEntries, mExistingDestinations));
+ updateEntries(constructEntryList(mEntryMap, mNonAggregatedEntries));
}
}
@@ -482,8 +481,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
@Override
public void handleMessage(Message msg) {
if (mRemainingDirectoryCount > 0) {
- updateEntries(constructEntryList(true,
- mEntryMap, mNonAggregatedEntries, mExistingDestinations));
+ updateEntries(constructEntryList(mEntryMap, mNonAggregatedEntries));
}
}
@@ -556,8 +554,9 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
return new DefaultFilter();
}
- private List<DirectorySearchParams> setupOtherDirectories(Cursor directoryCursor) {
- final PackageManager packageManager = mContext.getPackageManager();
+ public static List<DirectorySearchParams> setupOtherDirectories(Context context,
+ Cursor directoryCursor, Account account) {
+ final PackageManager packageManager = context.getPackageManager();
final List<DirectorySearchParams> paramsList = new ArrayList<DirectorySearchParams>();
DirectorySearchParams preferredDirectory = null;
while (directoryCursor.moveToNext()) {
@@ -594,8 +593,8 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
// If an account has been provided and we found a directory that
// corresponds to that account, place that directory second, directly
// underneath the local contacts.
- if (mAccount != null && mAccount.name.equals(params.accountName) &&
- mAccount.type.equals(params.accountType)) {
+ if (account != null && account.name.equals(params.accountName) &&
+ account.type.equals(params.accountType)) {
preferredDirectory = params;
} else {
paramsList.add(params);
@@ -633,7 +632,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
mDelayedMessageHandler.sendDelayedLoadMessage();
}
- private void putOneEntry(TemporaryEntry entry, boolean isAggregatedEntry,
+ private static void putOneEntry(TemporaryEntry entry, boolean isAggregatedEntry,
LinkedHashMap<Long, List<RecipientEntry>> entryMap,
List<RecipientEntry> nonAggregatedEntries,
Set<String> existingDestinations) {
@@ -648,7 +647,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
entry.displayName,
entry.displayNameSource,
entry.destination, entry.destinationType, entry.destinationLabel,
- entry.contactId, entry.dataId, entry.thumbnailUriString));
+ entry.contactId, entry.dataId, entry.thumbnailUriString, true));
} else if (entryMap.containsKey(entry.contactId)) {
// We already have a section for the person.
final List<RecipientEntry> entryList = entryMap.get(entry.contactId);
@@ -656,14 +655,14 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
entry.displayName,
entry.displayNameSource,
entry.destination, entry.destinationType, entry.destinationLabel,
- entry.contactId, entry.dataId, entry.thumbnailUriString));
+ entry.contactId, entry.dataId, entry.thumbnailUriString, true));
} else {
final List<RecipientEntry> entryList = new ArrayList<RecipientEntry>();
entryList.add(RecipientEntry.constructTopLevelEntry(
entry.displayName,
entry.displayNameSource,
entry.destination, entry.destinationType, entry.destinationLabel,
- entry.contactId, entry.dataId, entry.thumbnailUriString));
+ entry.contactId, entry.dataId, entry.thumbnailUriString, true));
entryMap.put(entry.contactId, entryList);
}
}
@@ -674,10 +673,8 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
* thread to get one from directories.
*/
private List<RecipientEntry> constructEntryList(
- boolean showMessageIfDirectoryLoadRemaining,
LinkedHashMap<Long, List<RecipientEntry>> entryMap,
- List<RecipientEntry> nonAggregatedEntries,
- Set<String> existingDestinations) {
+ List<RecipientEntry> nonAggregatedEntries) {
final List<RecipientEntry> entries = new ArrayList<RecipientEntry>();
int validEntryCount = 0;
for (Map.Entry<Long, List<RecipientEntry>> mapEntry : entryMap.entrySet()) {
@@ -708,6 +705,11 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
return entries;
}
+
+ protected interface EntriesUpdatedObserver {
+ public void onChanged(List<RecipientEntry> entries);
+ }
+
public void registerUpdateObserver(EntriesUpdatedObserver observer) {
mEntriesUpdatedObserver = observer;
}
@@ -906,7 +908,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
if (imageView != null) {
imageView.setVisibility(View.VISIBLE);
final byte[] photoBytes = entry.getPhotoBytes();
- if (photoBytes != null && imageView != null) {
+ if (photoBytes != null) {
final Bitmap photo = BitmapFactory.decodeByteArray(photoBytes, 0,
photoBytes.length);
imageView.setImageBitmap(photo);
@@ -975,11 +977,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
return android.R.id.icon;
}
- /**
- * Interface called before the BaseRecipientAdapter updates recipient
- * results in the popup window.
- */
- protected interface EntriesUpdatedObserver {
- public void onChanged(List<RecipientEntry> entries);
+ public Account getAccount() {
+ return mAccount;
}
}
diff --git a/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java b/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java
index 553890e..0693df2 100644
--- a/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java
+++ b/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java
@@ -16,9 +16,14 @@
package com.android.ex.chips;
+import android.accounts.Account;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.text.TextUtils;
import android.text.util.Rfc822Token;
import android.text.util.Rfc822Tokenizer;
import android.util.Log;
@@ -29,11 +34,16 @@ import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.ex.chips.BaseRecipientAdapter.DirectoryListQuery;
+import com.android.ex.chips.BaseRecipientAdapter.DirectorySearchParams;
import com.android.ex.chips.Queries.Query;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts
@@ -55,9 +65,17 @@ public class RecipientAlternatesAdapter extends CursorAdapter {
public static final int QUERY_TYPE_PHONE = 1;
private Query mQuery;
- public static HashMap<String, RecipientEntry> getMatchingRecipients(Context context,
- ArrayList<String> inAddresses) {
- return getMatchingRecipients(context, inAddresses, QUERY_TYPE_EMAIL);
+ public interface RecipientMatchCallback {
+ public void matchesFound(Map<String, RecipientEntry> results);
+ /**
+ * Called with all addresses that could not be resolved to valid recipients.
+ */
+ public void matchesNotFound(Set<String> unfoundAddresses);
+ }
+
+ public static void getMatchingRecipients(Context context, ArrayList<String> inAddresses,
+ Account account, RecipientMatchCallback callback) {
+ getMatchingRecipients(context, inAddresses, QUERY_TYPE_EMAIL, account, callback);
}
/**
@@ -67,10 +85,11 @@ public class RecipientAlternatesAdapter extends CursorAdapter {
*
* @param context Context.
* @param inAddresses Array of addresses on which to perform the lookup.
+ * @param callback RecipientMatchCallback called when a match or matches are found.
* @return HashMap<String,RecipientEntry>
*/
- public static HashMap<String, RecipientEntry> getMatchingRecipients(Context context,
- ArrayList<String> inAddresses, int addressType) {
+ public static void getMatchingRecipients(Context context, ArrayList<String> inAddresses,
+ int addressType, Account account, RecipientMatchCallback callback) {
Queries.Query query;
if (addressType == QUERY_TYPE_EMAIL) {
query = Queries.EMAIL;
@@ -78,12 +97,12 @@ public class RecipientAlternatesAdapter extends CursorAdapter {
query = Queries.PHONE;
}
int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size());
- String[] addresses = new String[addressesSize];
+ HashSet<String> addresses = new HashSet<String>();
StringBuilder bindString = new StringBuilder();
// Create the "?" string and set up arguments.
for (int i = 0; i < addressesSize; i++) {
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase());
- addresses[i] = (tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i));
+ addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i));
bindString.append("?");
if (i < addressesSize - 1) {
bindString.append(",");
@@ -94,49 +113,205 @@ public class RecipientAlternatesAdapter extends CursorAdapter {
Log.d(TAG, "Doing reverse lookup for " + addresses.toString());
}
- HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>();
- Cursor c = context.getContentResolver().query(
- query.getContentUri(),
- query.getProjection(),
- query.getProjection()[Queries.Query.DESTINATION] + " IN (" + bindString.toString()
- + ")", addresses, null);
-
- if (c != null) {
+ String[] addressArray = new String[addresses.size()];
+ addresses.toArray(addressArray);
+ HashMap<String, RecipientEntry> recipientEntries = null;
+ Cursor c = null;
+
+ try {
+ c = context.getContentResolver().query(
+ query.getContentUri(),
+ query.getProjection(),
+ query.getProjection()[Queries.Query.DESTINATION] + " IN ("
+ + bindString.toString() + ")", addressArray, null);
+ recipientEntries = processContactEntries(c);
+ callback.matchesFound(recipientEntries);
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ // See if any entries did not resolve; if so, we need to check other
+ // directories
+ final Set<String> matchesNotFound = new HashSet<String>();
+ if (recipientEntries.size() < addresses.size()) {
+ final List<DirectorySearchParams> paramsList;
+ Cursor directoryCursor = null;
try {
- if (c.moveToFirst()) {
- do {
- String address = c.getString(Queries.Query.DESTINATION);
- recipientEntries.put(address, RecipientEntry.constructTopLevelEntry(
- c.getString(Queries.Query.NAME),
- c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
- c.getString(Queries.Query.DESTINATION),
- c.getInt(Queries.Query.DESTINATION_TYPE),
- c.getString(Queries.Query.DESTINATION_LABEL),
- c.getLong(Queries.Query.CONTACT_ID),
- c.getLong(Queries.Query.DATA_ID),
- c.getString(Queries.Query.PHOTO_THUMBNAIL_URI)));
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Received reverse look up information for " + address
- + " RESULTS: "
- + " NAME : " + c.getString(Queries.Query.NAME)
- + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID)
- + " ADDRESS :" + c.getString(Queries.Query.DESTINATION));
+ directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI,
+ DirectoryListQuery.PROJECTION, null, null, null);
+ paramsList = BaseRecipientAdapter.setupOtherDirectories(context, directoryCursor,
+ account);
+ } finally {
+ if (directoryCursor != null) {
+ directoryCursor.close();
+ }
+ }
+ // Run a directory query for each unmatched recipient.
+ HashSet<String> unresolvedAddresses = new HashSet<String>();
+ for (String address : addresses) {
+ if (!recipientEntries.containsKey(address)) {
+ unresolvedAddresses.add(address);
+ }
+ }
+
+ matchesNotFound.addAll(unresolvedAddresses);
+
+ Cursor directoryContactsCursor = null;
+ for (String unresolvedAddress : unresolvedAddresses) {
+ for (int i = 0; i < paramsList.size(); i++) {
+ try {
+ directoryContactsCursor = doQuery(unresolvedAddress, 1,
+ paramsList.get(i).directoryId, account,
+ context.getContentResolver(), query);
+ } finally {
+ if (directoryContactsCursor != null
+ && directoryContactsCursor.getCount() == 0) {
+ directoryContactsCursor.close();
+ directoryContactsCursor = null;
+ } else {
+ break;
}
- } while (c.moveToNext());
+ }
+ }
+ if (directoryContactsCursor != null) {
+ try {
+ final Map<String, RecipientEntry> entries =
+ processContactEntries(directoryContactsCursor);
+
+ for (final String address : entries.keySet()) {
+ matchesNotFound.remove(address);
+ }
+
+ callback.matchesFound(entries);
+ } finally {
+ directoryContactsCursor.close();
+ }
}
- } finally {
- c.close();
}
}
+
+ callback.matchesNotFound(matchesNotFound);
+ }
+
+ private static HashMap<String, RecipientEntry> processContactEntries(Cursor c) {
+ HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>();
+ if (c != null && c.moveToFirst()) {
+ do {
+ String address = c.getString(Queries.Query.DESTINATION);
+
+ final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry(
+ c.getString(Queries.Query.NAME),
+ c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
+ c.getString(Queries.Query.DESTINATION),
+ c.getInt(Queries.Query.DESTINATION_TYPE),
+ c.getString(Queries.Query.DESTINATION_LABEL),
+ c.getLong(Queries.Query.CONTACT_ID),
+ c.getLong(Queries.Query.DATA_ID),
+ c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
+ true);
+
+ /*
+ * In certain situations, we may have two results for one address, where one of the
+ * results is just the email address, and the other has a name and photo, so we want
+ * to use the better one.
+ */
+ final RecipientEntry recipientEntry =
+ getBetterRecipient(recipientEntries.get(address), newRecipientEntry);
+
+ recipientEntries.put(address, recipientEntry);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Received reverse look up information for " + address
+ + " RESULTS: "
+ + " NAME : " + c.getString(Queries.Query.NAME)
+ + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID)
+ + " ADDRESS :" + c.getString(Queries.Query.DESTINATION));
+ }
+ } while (c.moveToNext());
+ }
return recipientEntries;
}
- public RecipientAlternatesAdapter(Context context, long contactId, long currentId, int viewId,
+ /**
+ * Given two {@link RecipientEntry}s for the same email address, this will return the one that
+ * contains more complete information for display purposes. Defaults to <code>entry2</code> if
+ * no significant differences are found.
+ */
+ static RecipientEntry getBetterRecipient(final RecipientEntry entry1,
+ final RecipientEntry entry2) {
+ // If only one has passed in, use it
+ if (entry2 == null) {
+ return entry1;
+ }
+
+ if (entry1 == null) {
+ return entry2;
+ }
+
+ // If only one has a display name, use it
+ if (!TextUtils.isEmpty(entry1.getDisplayName())
+ && TextUtils.isEmpty(entry2.getDisplayName())) {
+ return entry1;
+ }
+
+ if (!TextUtils.isEmpty(entry2.getDisplayName())
+ && TextUtils.isEmpty(entry1.getDisplayName())) {
+ return entry2;
+ }
+
+ // If only one has a display name that is not the same as the destination, use it
+ if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())
+ && TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) {
+ return entry1;
+ }
+
+ if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())
+ && TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) {
+ return entry2;
+ }
+
+ // If only one has a photo, use it
+ if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null)
+ && (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) {
+ return entry1;
+ }
+
+ if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null)
+ && (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) {
+ return entry2;
+ }
+
+ // Go with the second option as a default
+ return entry2;
+ }
+
+ private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId,
+ Account account, ContentResolver resolver, Query query) {
+ final Uri.Builder builder = query
+ .getContentFilterUri()
+ .buildUpon()
+ .appendPath(constraint.toString())
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES));
+ if (directoryId != null) {
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ }
+ if (account != null) {
+ builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name);
+ builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type);
+ }
+ final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null,
+ null);
+ return cursor;
+ }
+
+ public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
OnCheckedItemChangedListener listener) {
- this(context, contactId, currentId, viewId, QUERY_TYPE_EMAIL, listener);
+ this(context, contactId, currentId, QUERY_TYPE_EMAIL, listener);
}
- public RecipientAlternatesAdapter(Context context, long contactId, long currentId, int viewId,
+ public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
int queryMode, OnCheckedItemChangedListener listener) {
super(context, getCursorForConstruction(context, contactId, queryMode), 0);
mLayoutInflater = LayoutInflater.from(context);
@@ -233,7 +408,8 @@ public class RecipientAlternatesAdapter extends CursorAdapter {
c.getString(Queries.Query.DESTINATION_LABEL),
c.getLong(Queries.Query.CONTACT_ID),
c.getLong(Queries.Query.DATA_ID),
- c.getString(Queries.Query.PHOTO_THUMBNAIL_URI));
+ c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
+ true);
}
@Override
diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java
index 93ca4e8..d2e5806 100644
--- a/chips/src/com/android/ex/chips/RecipientEditTextView.java
+++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java
@@ -1,4 +1,5 @@
/*
+
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +17,18 @@
package com.android.ex.chips;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import android.app.Dialog;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -36,6 +49,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.text.Editable;
@@ -55,7 +69,6 @@ import android.text.util.Rfc822Tokenizer;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
-import android.util.Patterns;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.DragEvent;
@@ -81,17 +94,10 @@ import android.widget.MultiAutoCompleteTextView;
import android.widget.ScrollView;
import android.widget.TextView;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import com.android.ex.chips.RecipientAlternatesAdapter.RecipientMatchCallback;
+import com.android.ex.chips.recipientchip.DrawableRecipientChip;
+import com.android.ex.chips.recipientchip.InvisibleRecipientChip;
+import com.android.ex.chips.recipientchip.VisibleRecipientChip;
/**
* RecipientEditTextView is an auto complete text view for use with applications
@@ -104,12 +110,13 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
private static final char COMMIT_CHAR_COMMA = ',';
- private static final char NAME_WRAPPER_CHAR = '"';
-
private static final char COMMIT_CHAR_SEMICOLON = ';';
private static final char COMMIT_CHAR_SPACE = ' ';
+ private static final String SEPARATOR = String.valueOf(COMMIT_CHAR_COMMA)
+ + String.valueOf(COMMIT_CHAR_SPACE);
+
private static final String TAG = "RecipientEditTextView";
private static int DISMISS = "dismiss".hashCode();
@@ -145,7 +152,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
private Validator mValidator;
- private RecipientChip mSelectedChip;
+ private DrawableRecipientChip mSelectedChip;
private int mAlternatesLayout;
@@ -155,7 +162,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
private TextView mMoreItem;
- private final ArrayList<String> mPendingChips = new ArrayList<String>();
+ // VisibleForTesting
+ final ArrayList<String> mPendingChips = new ArrayList<String>();
private Handler mHandler;
@@ -167,9 +175,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
private ListPopupWindow mAddressPopup;
- private ArrayList<RecipientChip> mTemporaryRecipients;
+ // VisibleForTesting
+ ArrayList<DrawableRecipientChip> mTemporaryRecipients;
- private ArrayList<RecipientChip> mRemovedSpans;
+ private ArrayList<DrawableRecipientChip> mRemovedSpans;
private boolean mShouldShrink = true;
@@ -206,7 +215,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
+ "(1?[ ]*\\([0-9]+\\)[\\- \\.]*)?" // 1(<digits>)<sdd>*
+ "([0-9][0-9\\- \\.][0-9\\- \\.]+[0-9])"); // <digit><digit|sdd>+<digit>
-
private final Runnable mAddTextWatcher = new Runnable() {
@Override
public void run() {
@@ -282,7 +290,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
addTextChangedListener(mTextWatcher);
mGestureDetector = new GestureDetector(context, this);
setOnEditorActionListener(this);
- mMaxLines = getLineCount();
}
@Override
@@ -314,13 +321,15 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if ((outAttrs.imeOptions&EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
}
+
+ outAttrs.actionId = EditorInfo.IME_ACTION_DONE;
outAttrs.actionLabel = getContext().getString(R.string.done);
return connection;
}
- /*package*/ RecipientChip getLastChip() {
- RecipientChip last = null;
- RecipientChip[] chips = getSortedRecipients();
+ /*package*/ DrawableRecipientChip getLastChip() {
+ DrawableRecipientChip last = null;
+ DrawableRecipientChip[] chips = getSortedRecipients();
if (chips != null && chips.length > 0) {
last = chips[chips.length - 1];
}
@@ -331,7 +340,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
public void onSelectionChanged(int start, int end) {
// When selection changes, see if it is inside the chips area.
// If so, move the cursor back after the chips again.
- RecipientChip last = getLastChip();
+ DrawableRecipientChip last = getLastChip();
if (last != null && start < getSpannable().getSpanEnd(last)) {
// Grab the last chip and set the cursor to after it.
setSelection(Math.min(getSpannable().getSpanEnd(last) + 1, getText().length()));
@@ -370,22 +379,17 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
super.append(text, start, end);
if (!TextUtils.isEmpty(text) && TextUtils.getTrimmedLength(text) > 0) {
String displayString = text.toString();
- int separatorPos = displayString.lastIndexOf(COMMIT_CHAR_COMMA);
- // Verify that the separator pos is not within ""; if it is, look
- // past the closing quote. If there is no comma past ", this string
- // will resolve to an error chip.
- if (separatorPos > -1) {
- String parseDisplayString = displayString.substring(separatorPos);
- int endQuotedTextPos = parseDisplayString.indexOf(NAME_WRAPPER_CHAR);
- if (endQuotedTextPos > separatorPos) {
- separatorPos = parseDisplayString.lastIndexOf(COMMIT_CHAR_COMMA,
- endQuotedTextPos);
- }
+
+ if (!displayString.trim().endsWith(String.valueOf(COMMIT_CHAR_COMMA))) {
+ // We have no separator, so we should add it
+ super.append(SEPARATOR, 0, SEPARATOR.length());
+ displayString += SEPARATOR;
}
+
if (!TextUtils.isEmpty(displayString)
&& TextUtils.getTrimmedLength(displayString) > 0) {
mPendingChipsCount++;
- mPendingChips.add(text.toString());
+ mPendingChips.add(displayString);
}
}
// Put a message on the queue to make sure we ALWAYS handle pending
@@ -413,6 +417,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
return sExcessTopPadding;
}
+ @Override
public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
super.setAdapter(adapter);
((BaseRecipientAdapter) adapter)
@@ -476,7 +481,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
Editable editable = getText();
int end = getSelectionEnd();
int start = mTokenizer.findTokenStart(editable, end);
- RecipientChip[] chips = getSpannable().getSpans(start, end, RecipientChip.class);
+ DrawableRecipientChip[] chips =
+ getSpannable().getSpans(start, end, DrawableRecipientChip.class);
if ((chips == null || chips.length == 0)) {
Editable text = getText();
int whatEnd = mTokenizer.findTokenEnd(text, start);
@@ -524,7 +530,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
TextUtils.TruncateAt.END);
}
- private Bitmap createSelectedChip(RecipientEntry contact, TextPaint paint, Layout layout) {
+ private Bitmap createSelectedChip(RecipientEntry contact, TextPaint paint) {
// Ellipsize the text so that it takes AT MOST the entire width of the
// autocomplete text entry area. Make sure to leave space for padding
// on the sides.
@@ -533,7 +539,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
float[] widths = new float[1];
paint.getTextWidths(" ", widths);
CharSequence ellipsizedText = ellipsizeText(createChipDisplayText(contact), paint,
- calculateAvailableWidth(true) - deleteWidth - widths[0]);
+ calculateAvailableWidth() - deleteWidth - widths[0]);
// Make sure there is a minimum chip width so the user can ALWAYS
// tap a chip without difficulty.
@@ -566,7 +572,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
- private Bitmap createUnselectedChip(RecipientEntry contact, TextPaint paint, Layout layout,
+ private Bitmap createUnselectedChip(RecipientEntry contact, TextPaint paint,
boolean leaveBlankIconSpacer) {
// Ellipsize the text so that it takes AT MOST the entire width of the
// autocomplete text entry area. Make sure to leave space for padding
@@ -576,7 +582,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
float[] widths = new float[1];
paint.getTextWidths(" ", widths);
CharSequence ellipsizedText = ellipsizeText(createChipDisplayText(contact), paint,
- calculateAvailableWidth(false) - iconWidth - widths[0]);
+ calculateAvailableWidth() - iconWidth - widths[0]);
// Make sure there is a minimum chip width so the user can ALWAYS
// tap a chip without difficulty.
int width = Math.max(iconWidth * 2, (int) Math.floor(paint.measureText(ellipsizedText, 0,
@@ -646,25 +652,23 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* Get the background drawable for a RecipientChip.
*/
// Visible for testing.
- /*package*/ Drawable getChipBackground(RecipientEntry contact) {
- return (mValidator != null && mValidator.isValid(contact.getDestination())) ?
- mChipBackground : mInvalidChipBackground;
+ /* package */Drawable getChipBackground(RecipientEntry contact) {
+ return contact.isValid() ? mChipBackground : mInvalidChipBackground;
}
- private float getTextYOffset(String text, TextPaint paint, int height) {
+ private static float getTextYOffset(String text, TextPaint paint, int height) {
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int textHeight = bounds.bottom - bounds.top ;
return height - ((height - textHeight) / 2) - (int)paint.descent();
}
- private RecipientChip constructChipSpan(RecipientEntry contact, int offset, boolean pressed,
+ private DrawableRecipientChip constructChipSpan(RecipientEntry contact, boolean pressed,
boolean leaveIconSpace) throws NullPointerException {
if (mChipBackground == null) {
throw new NullPointerException(
"Unable to render any chips as setChipDimensions was not called.");
}
- Layout layout = getLayout();
TextPaint paint = getPaint();
float defaultSize = paint.getTextSize();
@@ -672,16 +676,16 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
Bitmap tmpBitmap;
if (pressed) {
- tmpBitmap = createSelectedChip(contact, paint, layout);
+ tmpBitmap = createSelectedChip(contact, paint);
} else {
- tmpBitmap = createUnselectedChip(contact, paint, layout, leaveIconSpace);
+ tmpBitmap = createUnselectedChip(contact, paint, leaveIconSpace);
}
// Pass the full text, un-ellipsized, to the chip.
Drawable result = new BitmapDrawable(getResources(), tmpBitmap);
result.setBounds(0, 0, tmpBitmap.getWidth(), tmpBitmap.getHeight());
- RecipientChip recipientChip = new RecipientChip(result, contact, offset);
+ DrawableRecipientChip recipientChip = new VisibleRecipientChip(result, contact);
// Return text to the original size.
paint.setTextSize(defaultSize);
paint.setColor(defaultColor);
@@ -706,7 +710,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* account the width of the EditTextView, any view padding, and padding
* that will be added to the chip.
*/
- private float calculateAvailableWidth(boolean pressed) {
+ private float calculateAvailableWidth() {
return getWidth() - getPaddingLeft() - getPaddingRight() - (mChipPadding * 2);
}
@@ -715,6 +719,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecipientEditTextView, 0,
0);
Resources r = getContext().getResources();
+
mChipBackground = a.getDrawable(R.styleable.RecipientEditTextView_chipBackground);
if (mChipBackground == null) {
mChipBackground = r.getDrawable(R.drawable.chip_background);
@@ -755,7 +760,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if (mInvalidChipBackground == null) {
mInvalidChipBackground = r.getDrawable(R.drawable.chip_background_invalid);
}
- mLineSpacingExtra = context.getResources().getDimension(R.dimen.line_spacing_extra);
+ mLineSpacingExtra = r.getDimension(R.dimen.line_spacing_extra);
+ mMaxLines = r.getInteger(R.integer.chips_max_lines);
TypedValue tv = new TypedValue();
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
mActionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources()
@@ -821,11 +827,11 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
private void checkChipWidths() {
// Check the widths of the associated chips.
- RecipientChip[] chips = getSortedRecipients();
+ DrawableRecipientChip[] chips = getSortedRecipients();
if (chips != null) {
Rect bounds;
- for (RecipientChip chip : chips) {
- bounds = chip.getDrawable().getBounds();
+ for (DrawableRecipientChip chip : chips) {
+ bounds = chip.getBounds();
if (getWidth() > 0 && bounds.right - bounds.left > getWidth()) {
// Need to redraw that chip.
replaceChip(chip, chip.getEntry());
@@ -853,7 +859,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
for (int i = 0; i < mPendingChips.size(); i++) {
String current = mPendingChips.get(i);
int tokenStart = editable.toString().indexOf(current);
- int tokenEnd = tokenStart + current.length();
+ // Always leave a space at the end between tokens.
+ int tokenEnd = tokenStart + current.length() - 1;
if (tokenStart >= 0) {
// When we have a valid token, include it with the token
// to the left.
@@ -861,7 +868,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
&& editable.charAt(tokenEnd) == COMMIT_CHAR_COMMA) {
tokenEnd++;
}
- createReplacementChip(tokenStart, tokenEnd, editable);
+ createReplacementChip(tokenStart, tokenEnd, editable, i < CHIP_LIMIT
+ || !mShouldShrink);
}
mPendingChipsCount--;
}
@@ -878,10 +886,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
} else {
// Create the "more" chip
mIndividualReplacements = new IndividualReplacementTask();
- mIndividualReplacements.execute(new ArrayList<RecipientChip>(
+ mIndividualReplacements.execute(new ArrayList<DrawableRecipientChip>(
mTemporaryRecipients.subList(0, CHIP_LIMIT)));
if (mTemporaryRecipients.size() > CHIP_LIMIT) {
- mTemporaryRecipients = new ArrayList<RecipientChip>(
+ mTemporaryRecipients = new ArrayList<DrawableRecipientChip>(
mTemporaryRecipients.subList(CHIP_LIMIT,
mTemporaryRecipients.size()));
} else {
@@ -915,17 +923,16 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
return;
}
// Find the last chip; eliminate any commit characters after it.
- RecipientChip[] chips = getSortedRecipients();
+ DrawableRecipientChip[] chips = getSortedRecipients();
+ Spannable spannable = getSpannable();
if (chips != null && chips.length > 0) {
int end;
- ImageSpan lastSpan;
mMoreChip = getMoreChip();
if (mMoreChip != null) {
- lastSpan = mMoreChip;
+ end = spannable.getSpanEnd(mMoreChip);
} else {
- lastSpan = getLastChip();
+ end = getSpannable().getSpanEnd(getLastChip());
}
- end = getSpannable().getSpanEnd(lastSpan);
Editable editable = getText();
int length = editable.length();
if (length > end) {
@@ -943,34 +950,35 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* Create a chip that represents just the email address of a recipient. At some later
* point, this chip will be attached to a real contact entry, if one exists.
*/
- private void createReplacementChip(int tokenStart, int tokenEnd, Editable editable) {
+ // VisibleForTesting
+ void createReplacementChip(int tokenStart, int tokenEnd, Editable editable,
+ boolean visible) {
if (alreadyHasChip(tokenStart, tokenEnd)) {
// There is already a chip present at this location.
// Don't recreate it.
return;
}
String token = editable.toString().substring(tokenStart, tokenEnd);
- int commitCharIndex = token.trim().lastIndexOf(COMMIT_CHAR_COMMA);
- if (commitCharIndex == token.length() - 1) {
- token = token.substring(0, token.length() - 1);
+ final String trimmedToken = token.trim();
+ int commitCharIndex = trimmedToken.lastIndexOf(COMMIT_CHAR_COMMA);
+ if (commitCharIndex != -1 && commitCharIndex == trimmedToken.length() - 1) {
+ token = trimmedToken.substring(0, trimmedToken.length() - 1);
}
RecipientEntry entry = createTokenizedEntry(token);
if (entry != null) {
- String destText = createAddressText(entry);
- SpannableString chipText = new SpannableString(destText);
- int end = getSelectionEnd();
- int start = mTokenizer != null ? mTokenizer.findTokenStart(getText(), end) : 0;
- RecipientChip chip = null;
+ DrawableRecipientChip chip = null;
try {
if (!mNoChips) {
- /* leave space for the contact icon if this is not just an email address */
- chip = constructChipSpan(
- entry,
- start,
- false,
- TextUtils.isEmpty(entry.getDisplayName())
- || TextUtils.equals(entry.getDisplayName(),
- entry.getDestination()));
+ /*
+ * leave space for the contact icon if this is not just an
+ * email address
+ */
+ boolean leaveSpace = TextUtils.isEmpty(entry.getDisplayName())
+ || TextUtils.equals(entry.getDisplayName(),
+ entry.getDestination());
+ chip = visible ?
+ constructChipSpan(entry, false, leaveSpace)
+ : new InvisibleRecipientChip(entry);
}
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
@@ -979,9 +987,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
// Add this chip to the list of entries "to replace"
if (chip != null) {
if (mTemporaryRecipients == null) {
- mTemporaryRecipients = new ArrayList<RecipientChip>();
+ mTemporaryRecipients = new ArrayList<DrawableRecipientChip>();
}
- chip.setOriginalText(chipText.toString());
+ chip.setOriginalText(token);
mTemporaryRecipients.add(chip);
}
}
@@ -999,70 +1007,68 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
return match.matches();
}
- private RecipientEntry createTokenizedEntry(String token) {
+ // VisibleForTesting
+ RecipientEntry createTokenizedEntry(final String token) {
if (TextUtils.isEmpty(token)) {
return null;
}
if (isPhoneQuery() && isPhoneNumber(token)) {
- return RecipientEntry
- .constructFakeEntry(token);
+ return RecipientEntry.constructFakePhoneEntry(token, true);
}
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(token);
String display = null;
- if (isValid(token) && tokens != null && tokens.length > 0) {
+ boolean isValid = isValid(token);
+ if (isValid && tokens != null && tokens.length > 0) {
// If we can get a name from tokenizing, then generate an entry from
// this.
display = tokens[0].getName();
if (!TextUtils.isEmpty(display)) {
- if (!isPhoneQuery()) {
- if (!TextUtils.isEmpty(token)) {
- token = token.trim();
- }
- char charAt = token.charAt(token.length() - 1);
- if (charAt == COMMIT_CHAR_COMMA || charAt == COMMIT_CHAR_SEMICOLON) {
- token = token.substring(0, token.length() - 1);
- }
- }
- return RecipientEntry.constructGeneratedEntry(display, token);
+ return RecipientEntry.constructGeneratedEntry(display, tokens[0].getAddress(),
+ isValid);
} else {
display = tokens[0].getAddress();
if (!TextUtils.isEmpty(display)) {
- return RecipientEntry.constructFakeEntry(display);
+ return RecipientEntry.constructFakeEntry(display, isValid);
}
}
}
// Unable to validate the token or to create a valid token from it.
// Just create a chip the user can edit.
String validatedToken = null;
- if (mValidator != null && !mValidator.isValid(token)) {
+ if (mValidator != null && !isValid) {
// Try fixing up the entry using the validator.
validatedToken = mValidator.fixText(token).toString();
if (!TextUtils.isEmpty(validatedToken)) {
if (validatedToken.contains(token)) {
- // protect against the case of a validator with a null domain,
+ // protect against the case of a validator with a null
+ // domain,
// which doesn't add a domain to the token
Rfc822Token[] tokenized = Rfc822Tokenizer.tokenize(validatedToken);
if (tokenized.length > 0) {
validatedToken = tokenized[0].getAddress();
+ isValid = true;
}
} else {
- // We ran into a case where the token was invalid and removed
- // by the validator. In this case, just use the original token
+ // We ran into a case where the token was invalid and
+ // removed
+ // by the validator. In this case, just use the original
+ // token
// and let the user sort out the error chip.
validatedToken = null;
+ isValid = false;
}
}
}
// Otherwise, fallback to just creating an editable email address chip.
- return RecipientEntry
- .constructFakeEntry(!TextUtils.isEmpty(validatedToken) ? validatedToken : token);
+ return RecipientEntry.constructFakeEntry(
+ !TextUtils.isEmpty(validatedToken) ? validatedToken : token, isValid);
}
private boolean isValid(String text) {
return mValidator == null ? true : mValidator.isValid(text);
}
- private String tokenizeAddress(String destination) {
+ private static String tokenizeAddress(String destination) {
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(destination);
if (tokens != null && tokens.length > 0) {
return tokens[0].getAddress();
@@ -1115,20 +1121,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- case KeyEvent.KEYCODE_DPAD_CENTER:
- if (event.hasNoModifiers()) {
- if (commitDefault()) {
- return true;
- }
- if (mSelectedChip != null) {
- clearSelectedChip();
- return true;
- } else if (focusNext()) {
- return true;
- }
- }
- break;
case KeyEvent.KEYCODE_TAB:
if (event.hasNoModifiers()) {
if (mSelectedChip != null) {
@@ -1136,9 +1128,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
} else {
commitDefault();
}
- if (focusNext()) {
- return true;
- }
}
break;
}
@@ -1246,10 +1235,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
return;
}
// Find the last chip.
- RecipientChip[] recips = getSortedRecipients();
+ DrawableRecipientChip[] recips = getSortedRecipients();
if (recips != null && recips.length > 0) {
- RecipientChip last = recips[recips.length - 1];
- RecipientChip beforeLast = null;
+ DrawableRecipientChip last = recips[recips.length - 1];
+ DrawableRecipientChip beforeLast = null;
if (recips.length > 1) {
beforeLast = recips[recips.length - 2];
}
@@ -1280,7 +1269,8 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if (mNoChips) {
return true;
}
- RecipientChip[] chips = getSpannable().getSpans(start, end, RecipientChip.class);
+ DrawableRecipientChip[] chips =
+ getSpannable().getSpans(start, end, DrawableRecipientChip.class);
if ((chips == null || chips.length == 0)) {
return false;
}
@@ -1299,7 +1289,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
setSelection(end);
String text = getText().toString().substring(start, end);
if (!TextUtils.isEmpty(text)) {
- RecipientEntry entry = RecipientEntry.constructFakeEntry(text);
+ RecipientEntry entry = RecipientEntry.constructFakeEntry(text, isValid(text));
QwertyKeyListener.markAsReplaced(editable, start, end, "");
CharSequence chipText = createChip(entry, false);
int selEnd = getSelectionEnd();
@@ -1323,8 +1313,21 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
removeChip(mSelectedChip);
}
- if (keyCode == KeyEvent.KEYCODE_ENTER && event.hasNoModifiers()) {
- return true;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ if (event.hasNoModifiers()) {
+ if (commitDefault()) {
+ return true;
+ }
+ if (mSelectedChip != null) {
+ clearSelectedChip();
+ return true;
+ } else if (focusNext()) {
+ return true;
+ }
+ }
+ break;
}
return super.onKeyDown(keyCode, event);
@@ -1335,11 +1338,11 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
return getText();
}
- private int getChipStart(RecipientChip chip) {
+ private int getChipStart(DrawableRecipientChip chip) {
return getSpannable().getSpanStart(chip);
}
- private int getChipEnd(RecipientChip chip) {
+ private int getChipEnd(DrawableRecipientChip chip) {
return getSpannable().getSpanEnd(chip);
}
@@ -1359,7 +1362,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
// If this is a RecipientChip, don't filter
// on its contents.
Spannable span = getSpannable();
- RecipientChip[] chips = span.getSpans(start, end, RecipientChip.class);
+ DrawableRecipientChip[] chips = span.getSpans(start, end, DrawableRecipientChip.class);
if (chips != null && chips.length > 0) {
return;
}
@@ -1417,7 +1420,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
float x = event.getX();
float y = event.getY();
int offset = putOffsetInRange(getOffsetForPosition(x, y));
- RecipientChip currentChip = findChip(offset);
+ DrawableRecipientChip currentChip = findChip(offset);
if (currentChip != null) {
if (action == MotionEvent.ACTION_UP) {
if (mSelectedChip != null && mSelectedChip != currentChip) {
@@ -1449,44 +1452,54 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
}
- private void showAlternates(RecipientChip currentChip, ListPopupWindow alternatesPopup,
- int width, Context context) {
- int line = getLayout().getLineForOffset(getChipStart(currentChip));
- int bottom;
- if (line == getLineCount() -1) {
- bottom = 0;
- } else {
- bottom = -(int) ((mChipHeight + (2 * mLineSpacingExtra)) * (Math.abs(getLineCount() - 1
- - line)));
- }
- // Align the alternates popup with the left side of the View,
- // regardless of the position of the chip tapped.
- alternatesPopup.setWidth(width);
- alternatesPopup.setAnchorView(this);
- alternatesPopup.setVerticalOffset(bottom);
- alternatesPopup.setAdapter(createAlternatesAdapter(currentChip));
- alternatesPopup.setOnItemClickListener(mAlternatesListener);
- // Clear the checked item.
- mCheckedItem = -1;
- alternatesPopup.show();
- ListView listView = alternatesPopup.getListView();
- listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- // Checked item would be -1 if the adapter has not
- // loaded the view that should be checked yet. The
- // variable will be set correctly when onCheckedItemChanged
- // is called in a separate thread.
- if (mCheckedItem != -1) {
- listView.setItemChecked(mCheckedItem, true);
- mCheckedItem = -1;
- }
+ private void showAlternates(final DrawableRecipientChip currentChip,
+ final ListPopupWindow alternatesPopup, final int width) {
+ new AsyncTask<Void, Void, ListAdapter>() {
+ @Override
+ protected ListAdapter doInBackground(final Void... params) {
+ return createAlternatesAdapter(currentChip);
+ }
+
+ @Override
+ protected void onPostExecute(final ListAdapter result) {
+ int line = getLayout().getLineForOffset(getChipStart(currentChip));
+ int bottom;
+ if (line == getLineCount() -1) {
+ bottom = 0;
+ } else {
+ bottom = -(int) ((mChipHeight + (2 * mLineSpacingExtra)) * (Math
+ .abs(getLineCount() - 1 - line)));
+ }
+ // Align the alternates popup with the left side of the View,
+ // regardless of the position of the chip tapped.
+ alternatesPopup.setWidth(width);
+ alternatesPopup.setAnchorView(RecipientEditTextView.this);
+ alternatesPopup.setVerticalOffset(bottom);
+ alternatesPopup.setAdapter(result);
+ alternatesPopup.setOnItemClickListener(mAlternatesListener);
+ // Clear the checked item.
+ mCheckedItem = -1;
+ alternatesPopup.show();
+ ListView listView = alternatesPopup.getListView();
+ listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ // Checked item would be -1 if the adapter has not
+ // loaded the view that should be checked yet. The
+ // variable will be set correctly when onCheckedItemChanged
+ // is called in a separate thread.
+ if (mCheckedItem != -1) {
+ listView.setItemChecked(mCheckedItem, true);
+ mCheckedItem = -1;
+ }
+ }
+ }.execute((Void[]) null);
}
- private ListAdapter createAlternatesAdapter(RecipientChip chip) {
+ private ListAdapter createAlternatesAdapter(DrawableRecipientChip chip) {
return new RecipientAlternatesAdapter(getContext(), chip.getContactId(), chip.getDataId(),
- mAlternatesLayout, ((BaseRecipientAdapter)getAdapter()).getQueryType(), this);
+ ((BaseRecipientAdapter)getAdapter()).getQueryType(), this);
}
- private ListAdapter createSingleAddressAdapter(RecipientChip currentChip) {
+ private ListAdapter createSingleAddressAdapter(DrawableRecipientChip currentChip) {
return new SingleRecipientArrayAdapter(getContext(), mAlternatesLayout, currentChip
.getEntry());
}
@@ -1530,18 +1543,19 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
return offset;
}
- private int findText(Editable text, int offset) {
+ private static int findText(Editable text, int offset) {
if (text.charAt(offset) != ' ') {
return offset;
}
return -1;
}
- private RecipientChip findChip(int offset) {
- RecipientChip[] chips = getSpannable().getSpans(0, getText().length(), RecipientChip.class);
+ private DrawableRecipientChip findChip(int offset) {
+ DrawableRecipientChip[] chips =
+ getSpannable().getSpans(0, getText().length(), DrawableRecipientChip.class);
// Find the chip that contains this offset.
for (int i = 0; i < chips.length; i++) {
- RecipientChip chip = chips[i];
+ DrawableRecipientChip chip = chips[i];
int start = getChipStart(chip);
int end = getChipEnd(chip);
if (offset >= start && offset <= end) {
@@ -1588,14 +1602,6 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if (TextUtils.isEmpty(display) || TextUtils.equals(display, address)) {
display = null;
}
- if (address != null && !(isPhoneQuery() && isPhoneNumber(address))) {
- // Tokenize out the address in case the address already
- // contained the username as well.
- Rfc822Token[] tokenized = Rfc822Tokenizer.tokenize(address);
- if (tokenized != null && tokenized.length > 0) {
- address = tokenized[0].getAddress();
- }
- }
if (!TextUtils.isEmpty(display)) {
return display;
} else if (!TextUtils.isEmpty(address)){
@@ -1612,13 +1618,11 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
SpannableString chipText = null;
// Always leave a blank space at the end of a chip.
- int end = getSelectionEnd();
- int start = mTokenizer.findTokenStart(getText(), end);
- int textLength = displayText.length()-1;
+ int textLength = displayText.length() - 1;
chipText = new SpannableString(displayText);
if (!mNoChips) {
try {
- RecipientChip chip = constructChipSpan(entry, start, pressed,
+ DrawableRecipientChip chip = constructChipSpan(entry, pressed,
false /* leave space for contact icon */);
chipText.setSpan(chip, 0, textLength,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -1637,6 +1641,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);
}
@@ -1671,12 +1678,12 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
String destination = item.getDestination();
if (!isPhoneQuery() && item.getContactId() == RecipientEntry.GENERATED_CONTACT) {
entry = RecipientEntry.constructGeneratedEntry(item.getDisplayName(),
- destination);
+ destination, item.isValid());
} else if (RecipientEntry.isCreatedRecipient(item.getContactId())
&& (TextUtils.isEmpty(item.getDisplayName())
|| TextUtils.equals(item.getDisplayName(), destination)
|| (mValidator != null && !mValidator.isValid(destination)))) {
- entry = RecipientEntry.constructFakeEntry(destination);
+ entry = RecipientEntry.constructFakeEntry(destination, item.isValid());
} else {
entry = item;
}
@@ -1686,9 +1693,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
/** Returns a collection of contact Id for each chip inside this View. */
/* package */ Collection<Long> getContactIds() {
final Set<Long> result = new HashSet<Long>();
- RecipientChip[] chips = getSortedRecipients();
+ DrawableRecipientChip[] chips = getSortedRecipients();
if (chips != null) {
- for (RecipientChip chip : chips) {
+ for (DrawableRecipientChip chip : chips) {
result.add(chip.getContactId());
}
}
@@ -1699,9 +1706,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
/** Returns a collection of data Id for each chip inside this View. May be null. */
/* package */ Collection<Long> getDataIds() {
final Set<Long> result = new HashSet<Long>();
- RecipientChip [] chips = getSortedRecipients();
+ DrawableRecipientChip [] chips = getSortedRecipients();
if (chips != null) {
- for (RecipientChip chip : chips) {
+ for (DrawableRecipientChip chip : chips) {
result.add(chip.getDataId());
}
}
@@ -1709,16 +1716,16 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
// Visible for testing.
- /* package */RecipientChip[] getSortedRecipients() {
- RecipientChip[] recips = getSpannable()
- .getSpans(0, getText().length(), RecipientChip.class);
- ArrayList<RecipientChip> recipientsList = new ArrayList<RecipientChip>(Arrays
- .asList(recips));
+ /* package */DrawableRecipientChip[] getSortedRecipients() {
+ DrawableRecipientChip[] recips = getSpannable()
+ .getSpans(0, getText().length(), DrawableRecipientChip.class);
+ ArrayList<DrawableRecipientChip> recipientsList = new ArrayList<DrawableRecipientChip>(
+ Arrays.asList(recips));
final Spannable spannable = getSpannable();
- Collections.sort(recipientsList, new Comparator<RecipientChip>() {
+ Collections.sort(recipientsList, new Comparator<DrawableRecipientChip>() {
@Override
- public int compare(RecipientChip first, RecipientChip second) {
+ public int compare(DrawableRecipientChip first, DrawableRecipientChip second) {
int firstStart = spannable.getSpanStart(first);
int secondStart = spannable.getSpanStart(second);
if (firstStart < secondStart) {
@@ -1730,7 +1737,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
}
});
- return recipientsList.toArray(new RecipientChip[recipientsList.size()]);
+ return recipientsList.toArray(new DrawableRecipientChip[recipientsList.size()]);
}
@Override
@@ -1837,7 +1844,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if (tempMore.length > 0) {
getSpannable().removeSpan(tempMore[0]);
}
- RecipientChip[] recipients = getSortedRecipients();
+ DrawableRecipientChip[] recipients = getSortedRecipients();
if (recipients == null || recipients.length <= CHIP_LIMIT) {
mMoreChip = null;
@@ -1847,7 +1854,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
int numRecipients = recipients.length;
int overage = numRecipients - CHIP_LIMIT;
MoreImageSpan moreSpan = createMoreSpan(overage);
- mRemovedSpans = new ArrayList<RecipientChip>();
+ mRemovedSpans = new ArrayList<DrawableRecipientChip>();
int totalReplaceStart = 0;
int totalReplaceEnd = 0;
Editable text = getText();
@@ -1894,7 +1901,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
// Re-add the spans that were removed.
if (mRemovedSpans != null && mRemovedSpans.size() > 0) {
// Recreate each removed span.
- RecipientChip[] recipients = getSortedRecipients();
+ DrawableRecipientChip[] recipients = getSortedRecipients();
// Start the search for tokens after the last currently visible
// chip.
if (recipients == null || recipients.length == 0) {
@@ -1902,7 +1909,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
int end = span.getSpanEnd(recipients[recipients.length - 1]);
Editable editable = getText();
- for (RecipientChip chip : mRemovedSpans) {
+ for (DrawableRecipientChip chip : mRemovedSpans) {
int chipStart;
int chipEnd;
String token;
@@ -1937,7 +1944,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* @return A RecipientChip in the selected state or null if the chip
* just contained an email address.
*/
- private RecipientChip selectChip(RecipientChip currentChip) {
+ private DrawableRecipientChip selectChip(DrawableRecipientChip currentChip) {
if (shouldShowEditableText(currentChip)) {
CharSequence text = currentChip.getValue();
Editable editable = getText();
@@ -1950,18 +1957,18 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
setSelection(editable.length());
editable.append(text);
return constructChipSpan(
- RecipientEntry.constructFakeEntry((String) text),
- getSelectionStart(), true, false);
+ RecipientEntry.constructFakeEntry((String) text, isValid(text.toString())),
+ true, false);
} else if (currentChip.getContactId() == RecipientEntry.GENERATED_CONTACT) {
int start = getChipStart(currentChip);
int end = getChipEnd(currentChip);
getSpannable().removeSpan(currentChip);
- RecipientChip newChip;
+ DrawableRecipientChip newChip;
try {
if (mNoChips) {
return null;
}
- newChip = constructChipSpan(currentChip.getEntry(), start, true, false);
+ newChip = constructChipSpan(currentChip.getEntry(), true, false);
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
return null;
@@ -1977,16 +1984,16 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if (shouldShowEditableText(newChip)) {
scrollLineIntoView(getLayout().getLineForOffset(getChipStart(newChip)));
}
- showAddress(newChip, mAddressPopup, getWidth(), getContext());
+ showAddress(newChip, mAddressPopup, getWidth());
setCursorVisible(false);
return newChip;
} else {
int start = getChipStart(currentChip);
int end = getChipEnd(currentChip);
getSpannable().removeSpan(currentChip);
- RecipientChip newChip;
+ DrawableRecipientChip newChip;
try {
- newChip = constructChipSpan(currentChip.getEntry(), start, true, false);
+ newChip = constructChipSpan(currentChip.getEntry(), true, false);
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
return null;
@@ -2002,20 +2009,20 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if (shouldShowEditableText(newChip)) {
scrollLineIntoView(getLayout().getLineForOffset(getChipStart(newChip)));
}
- showAlternates(newChip, mAlternatesPopup, getWidth(), getContext());
+ showAlternates(newChip, mAlternatesPopup, getWidth());
setCursorVisible(false);
return newChip;
}
}
- private boolean shouldShowEditableText(RecipientChip currentChip) {
+ private boolean shouldShowEditableText(DrawableRecipientChip currentChip) {
long contactId = currentChip.getContactId();
return contactId == RecipientEntry.INVALID_CONTACT
|| (!isPhoneQuery() && contactId == RecipientEntry.GENERATED_CONTACT);
}
- private void showAddress(final RecipientChip currentChip, final ListPopupWindow popup,
- int width, Context context) {
+ private void showAddress(final DrawableRecipientChip currentChip, final ListPopupWindow popup,
+ int width) {
int line = getLayout().getLineForOffset(getChipStart(currentChip));
int bottom = calculateOffsetFromBottom(line);
// Align the alternates popup with the left side of the View,
@@ -2042,7 +2049,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* the chip without a delete icon and with an unfocused background. This is
* called when the RecipientChip no longer has focus.
*/
- private void unselectChip(RecipientChip chip) {
+ private void unselectChip(DrawableRecipientChip chip) {
int start = getChipStart(chip);
int end = getChipEnd(chip);
Editable editable = getText();
@@ -2057,7 +2064,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
editable.removeSpan(chip);
try {
if (!mNoChips) {
- editable.setSpan(constructChipSpan(chip.getEntry(), start, false, false),
+ editable.setSpan(constructChipSpan(chip.getEntry(), false, false),
start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} catch (NullPointerException e) {
@@ -2080,9 +2087,10 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* right after the selected chip.
* @return boolean
*/
- private boolean isInDelete(RecipientChip chip, int offset, float x, float y) {
+ private boolean isInDelete(DrawableRecipientChip chip, int offset, float x, float y) {
// Figure out the bounds of this chip and whether or not
// the user clicked in the X portion.
+ // TODO: Should x and y be used, or removed?
return chip.isSelected() && offset == getChipEnd(chip);
}
@@ -2090,7 +2098,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* Remove the chip and any text associated with it from the RecipientEditTextView.
*/
// Visible for testing.
- /*pacakge*/ void removeChip(RecipientChip chip) {
+ /*pacakge*/ void removeChip(DrawableRecipientChip chip) {
Spannable spannable = getSpannable();
int spanStart = spannable.getSpanStart(chip);
int spanEnd = spannable.getSpanEnd(chip);
@@ -2119,7 +2127,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* that uses the contact data provided.
*/
// Visible for testing.
- /*package*/ void replaceChip(RecipientChip chip, RecipientEntry entry) {
+ /*package*/ void replaceChip(DrawableRecipientChip chip, RecipientEntry entry) {
boolean wasSelected = chip == mSelectedChip;
if (wasSelected) {
mSelectedChip = null;
@@ -2157,7 +2165,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* event, see if that event was in the delete icon. If so, delete it.
* Otherwise, unselect the chip.
*/
- public void onClick(RecipientChip chip, int offset, float x, float y) {
+ public void onClick(DrawableRecipientChip chip, int offset, float x, float y) {
if (chip.isSelected()) {
if (isInDelete(chip, offset, x, y)) {
removeChip(chip);
@@ -2186,9 +2194,9 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
if (TextUtils.isEmpty(s)) {
// Remove all the chips spans.
Spannable spannable = getSpannable();
- RecipientChip[] chips = spannable.getSpans(0, getText().length(),
- RecipientChip.class);
- for (RecipientChip chip : chips) {
+ DrawableRecipientChip[] chips = spannable.getSpans(0, getText().length(),
+ DrawableRecipientChip.class);
+ for (DrawableRecipientChip chip : chips) {
spannable.removeSpan(chip);
}
if (mMoreChip != null) {
@@ -2202,16 +2210,23 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
return;
}
// If the user is editing a chip, don't clear it.
- if (mSelectedChip != null
- && shouldShowEditableText(mSelectedChip)) {
- setCursorVisible(true);
- setSelection(getText().length());
- clearSelectedChip();
+ if (mSelectedChip != null) {
+ if (!isGeneratedContact(mSelectedChip)) {
+ setCursorVisible(true);
+ setSelection(getText().length());
+ clearSelectedChip();
+ } else {
+ return;
+ }
}
int length = s.length();
// Make sure there is content there to parse and that it is
// not just the commit character.
if (length > 1) {
+ if (lastCharacterIsCommitCharacter(s)) {
+ commitByCharacter();
+ return;
+ }
char last;
int end = getSelectionEnd() == 0 ? 0 : getSelectionEnd() - 1;
int len = length() - 1;
@@ -2220,9 +2235,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
} else {
last = s.charAt(len);
}
- if (last == COMMIT_CHAR_SEMICOLON || last == COMMIT_CHAR_COMMA) {
- commitByCharacter();
- } else if (last == COMMIT_CHAR_SPACE) {
+ if (last == COMMIT_CHAR_SPACE) {
if (!isPhoneQuery()) {
// Check if this is a valid email address. If it is,
// commit it.
@@ -2241,14 +2254,15 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
- // This is a delete; check to see if the insertion point is on a space
+ // The user deleted some text OR some text was replaced; check to
+ // see if the insertion point is on a space
// following a chip.
if (before - count == 1) {
// If the item deleted is a space, and the thing before the
// space is a chip, delete the entire span.
int selStart = getSelectionStart();
- RecipientChip[] repl = getSpannable().getSpans(selStart, selStart,
- RecipientChip.class);
+ DrawableRecipientChip[] repl = getSpannable().getSpans(selStart, selStart,
+ DrawableRecipientChip.class);
if (repl.length > 0) {
// There is a chip there! Just remove it.
Editable editable = getText();
@@ -2262,6 +2276,14 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
editable.delete(tokenStart, tokenEnd);
getSpannable().removeSpan(repl[0]);
}
+ } else if (count > before) {
+ if (mSelectedChip != null
+ && isGeneratedContact(mSelectedChip)) {
+ if (lastCharacterIsCommitCharacter(s)) {
+ commitByCharacter();
+ return;
+ }
+ }
}
}
@@ -2271,6 +2293,24 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
}
+ public boolean lastCharacterIsCommitCharacter(CharSequence s) {
+ char last;
+ int end = getSelectionEnd() == 0 ? 0 : getSelectionEnd() - 1;
+ int len = length() - 1;
+ if (end != len) {
+ last = s.charAt(end);
+ } else {
+ last = s.charAt(len);
+ }
+ return last == COMMIT_CHAR_COMMA || last == COMMIT_CHAR_SEMICOLON;
+ }
+
+ public boolean isGeneratedContact(DrawableRecipientChip chip) {
+ long contactId = chip.getContactId();
+ return contactId == RecipientEntry.INVALID_CONTACT
+ || (!isPhoneQuery() && contactId == RecipientEntry.GENERATED_CONTACT);
+ }
+
/**
* Handles pasting a {@link ClipData} to this {@link RecipientEditTextView}.
*/
@@ -2309,7 +2349,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
private void handlePasteAndReplace() {
- ArrayList<RecipientChip> created = handlePaste();
+ ArrayList<DrawableRecipientChip> created = handlePaste();
if (created != null && created.size() > 0) {
// Perform reverse lookups on the pasted contacts.
IndividualReplacementTask replace = new IndividualReplacementTask();
@@ -2318,27 +2358,30 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
// Visible for testing.
- /* package */ArrayList<RecipientChip> handlePaste() {
+ /* package */ArrayList<DrawableRecipientChip> handlePaste() {
String text = getText().toString();
int originalTokenStart = mTokenizer.findTokenStart(text, getSelectionEnd());
String lastAddress = text.substring(originalTokenStart);
int tokenStart = originalTokenStart;
- int prevTokenStart = tokenStart;
- RecipientChip findChip = null;
- ArrayList<RecipientChip> created = new ArrayList<RecipientChip>();
+ int prevTokenStart = 0;
+ DrawableRecipientChip findChip = null;
+ ArrayList<DrawableRecipientChip> created = new ArrayList<DrawableRecipientChip>();
if (tokenStart != 0) {
// There are things before this!
- while (tokenStart != 0 && findChip == null) {
+ while (tokenStart != 0 && findChip == null && tokenStart != prevTokenStart) {
prevTokenStart = tokenStart;
tokenStart = mTokenizer.findTokenStart(text, tokenStart);
findChip = findChip(tokenStart);
+ if (tokenStart == originalTokenStart && findChip == null) {
+ break;
+ }
}
if (tokenStart != originalTokenStart) {
if (findChip != null) {
tokenStart = prevTokenStart;
}
int tokenEnd;
- RecipientChip createdChip;
+ DrawableRecipientChip createdChip;
while (tokenStart < originalTokenStart) {
tokenEnd = movePastTerminators(mTokenizer.findTokenEnd(getText().toString(),
tokenStart));
@@ -2382,12 +2425,12 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
private class RecipientReplacementTask extends AsyncTask<Void, Void, Void> {
- private RecipientChip createFreeChip(RecipientEntry entry) {
+ private DrawableRecipientChip createFreeChip(RecipientEntry entry) {
try {
if (mNoChips) {
return null;
}
- return constructChipSpan(entry, -1, false,
+ return constructChipSpan(entry, false,
false /*leave space for contact icon */);
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
@@ -2396,6 +2439,35 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
}
@Override
+ protected void onPreExecute() {
+ // Ensure everything is in chip-form already, so we don't have text that slowly gets
+ // replaced
+ final List<DrawableRecipientChip> originalRecipients =
+ new ArrayList<DrawableRecipientChip>();
+ final DrawableRecipientChip[] existingChips = getSortedRecipients();
+ for (int i = 0; i < existingChips.length; i++) {
+ originalRecipients.add(existingChips[i]);
+ }
+ if (mRemovedSpans != null) {
+ originalRecipients.addAll(mRemovedSpans);
+ }
+
+ final List<DrawableRecipientChip> replacements =
+ new ArrayList<DrawableRecipientChip>(originalRecipients.size());
+
+ for (final DrawableRecipientChip chip : originalRecipients) {
+ if (RecipientEntry.isCreatedRecipient(chip.getEntry().getContactId())
+ && getSpannable().getSpanStart(chip) != -1) {
+ replacements.add(createFreeChip(chip.getEntry()));
+ } else {
+ replacements.add(null);
+ }
+ }
+
+ processReplacements(originalRecipients, replacements);
+ }
+
+ @Override
protected Void doInBackground(Void... params) {
if (mIndividualReplacements != null) {
mIndividualReplacements.cancel(true);
@@ -2403,115 +2475,192 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
// For each chip in the list, look up the matching contact.
// If there is a match, replace that chip with the matching
// chip.
- final ArrayList<RecipientChip> originalRecipients = new ArrayList<RecipientChip>();
- RecipientChip[] existingChips = getSortedRecipients();
+ final ArrayList<DrawableRecipientChip> recipients =
+ new ArrayList<DrawableRecipientChip>();
+ DrawableRecipientChip[] existingChips = getSortedRecipients();
for (int i = 0; i < existingChips.length; i++) {
- originalRecipients.add(existingChips[i]);
+ recipients.add(existingChips[i]);
}
if (mRemovedSpans != null) {
- originalRecipients.addAll(mRemovedSpans);
+ recipients.addAll(mRemovedSpans);
}
ArrayList<String> addresses = new ArrayList<String>();
- RecipientChip chip;
- for (int i = 0; i < originalRecipients.size(); i++) {
- chip = originalRecipients.get(i);
+ DrawableRecipientChip chip;
+ for (int i = 0; i < recipients.size(); i++) {
+ chip = recipients.get(i);
if (chip != null) {
addresses.add(createAddressText(chip.getEntry()));
}
}
- HashMap<String, RecipientEntry> entries = RecipientAlternatesAdapter
- .getMatchingRecipients(getContext(), addresses);
- final ArrayList<RecipientChip> replacements = new ArrayList<RecipientChip>();
- for (final RecipientChip temp : originalRecipients) {
- RecipientEntry entry = null;
- if (RecipientEntry.isCreatedRecipient(temp.getEntry().getContactId())
- && getSpannable().getSpanStart(temp) != -1) {
- // Replace this.
- entry = createValidatedEntry(entries.get(tokenizeAddress(temp.getEntry()
- .getDestination())));
- }
- if (entry != null) {
- replacements.add(createFreeChip(entry));
- } else {
- replacements.add(temp);
- }
+ final BaseRecipientAdapter adapter = (BaseRecipientAdapter) getAdapter();
+ if (adapter == null) {
+ return null;
}
+ RecipientAlternatesAdapter.getMatchingRecipients(getContext(), addresses,
+ adapter.getAccount(), new RecipientMatchCallback() {
+ @Override
+ public void matchesFound(Map<String, RecipientEntry> entries) {
+ final ArrayList<DrawableRecipientChip> replacements =
+ new ArrayList<DrawableRecipientChip>();
+ for (final DrawableRecipientChip temp : recipients) {
+ RecipientEntry entry = null;
+ if (temp != null && RecipientEntry.isCreatedRecipient(
+ temp.getEntry().getContactId())
+ && getSpannable().getSpanStart(temp) != -1) {
+ // Replace this.
+ entry = createValidatedEntry(
+ entries.get(tokenizeAddress(temp.getEntry()
+ .getDestination())));
+ }
+ if (entry != null) {
+ replacements.add(createFreeChip(entry));
+ } else {
+ replacements.add(null);
+ }
+ }
+ processReplacements(recipients, replacements);
+ }
+
+ @Override
+ public void matchesNotFound(final Set<String> unfoundAddresses) {
+ final List<DrawableRecipientChip> replacements =
+ new ArrayList<DrawableRecipientChip>(unfoundAddresses.size());
+
+ for (final DrawableRecipientChip temp : recipients) {
+ if (temp != null && RecipientEntry.isCreatedRecipient(
+ temp.getEntry().getContactId())
+ && getSpannable().getSpanStart(temp) != -1) {
+ if (unfoundAddresses.contains(
+ temp.getEntry().getDestination())) {
+ replacements.add(createFreeChip(temp.getEntry()));
+ } else {
+ replacements.add(null);
+ }
+ } else {
+ replacements.add(null);
+ }
+ }
+
+ processReplacements(recipients, replacements);
+ }
+ });
+ return null;
+ }
+
+ private void processReplacements(final List<DrawableRecipientChip> recipients,
+ final List<DrawableRecipientChip> replacements) {
if (replacements != null && replacements.size() > 0) {
- mHandler.post(new Runnable() {
+ 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 (RecipientChip chip : originalRecipients) {
- // Find the location of the chip in the text currently shown.
- start = oldText.getSpanStart(chip);
- if (start != -1) {
- end = oldText.getSpanEnd(chip);
- oldText.removeSpan(chip);
- RecipientChip replacement = replacements.get(i);
- // Make sure we always have just 1 space at the
- // end to separate this chip from the next chip.
- SpannableString displayText = new SpannableString(
- createAddressText(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);
- replacement.setOriginalText(displayText.toString());
+ for (final DrawableRecipientChip chip : recipients) {
+ final DrawableRecipientChip replacement = replacements.get(i);
+ if (replacement != null) {
+ final RecipientEntry oldEntry = chip.getEntry();
+ final RecipientEntry newEntry = replacement.getEntry();
+ final boolean isBetter =
+ RecipientAlternatesAdapter.getBetterRecipient(
+ oldEntry, newEntry) == newEntry;
+
+ if (isBetter) {
+ // Find the location of the chip in the text currently shown.
+ 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.
+ final int end =
+ Math.min(text.getSpanEnd(chip) + 1, text.length());
+ text.removeSpan(chip);
+ // Make sure we always have just 1 space at the end to
+ // separate this chip from the next chip.
+ final SpannableString displayText =
+ new SpannableString(createAddressText(
+ 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.
+ text.replace(start, end, displayText);
+ replacement.setOriginalText(displayText.toString());
+ replacements.set(i, null);
+
+ recipients.set(i, replacement);
+ }
+ }
}
i++;
}
- originalRecipients.clear();
+ setText(text);
}
- });
+ };
+
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ runnable.run();
+ } else {
+ mHandler.post(runnable);
+ }
}
- return null;
}
}
- private class IndividualReplacementTask extends AsyncTask<Object, Void, Void> {
- @SuppressWarnings("unchecked")
+ private class IndividualReplacementTask
+ extends AsyncTask<ArrayList<DrawableRecipientChip>, Void, Void> {
@Override
- protected Void doInBackground(Object... params) {
+ protected Void doInBackground(ArrayList<DrawableRecipientChip>... params) {
// For each chip in the list, look up the matching contact.
// If there is a match, replace that chip with the matching
// chip.
- final ArrayList<RecipientChip> originalRecipients =
- (ArrayList<RecipientChip>) params[0];
+ final ArrayList<DrawableRecipientChip> originalRecipients = params[0];
ArrayList<String> addresses = new ArrayList<String>();
- RecipientChip chip;
+ DrawableRecipientChip chip;
for (int i = 0; i < originalRecipients.size(); i++) {
chip = originalRecipients.get(i);
if (chip != null) {
addresses.add(createAddressText(chip.getEntry()));
}
}
- HashMap<String, RecipientEntry> entries = RecipientAlternatesAdapter
- .getMatchingRecipients(getContext(), addresses);
- for (final RecipientChip temp : originalRecipients) {
- if (RecipientEntry.isCreatedRecipient(temp.getEntry().getContactId())
- && getSpannable().getSpanStart(temp) != -1) {
- // Replace this.
- RecipientEntry entry = createValidatedEntry(entries.get(tokenizeAddress(
- temp.getEntry().getDestination()).toLowerCase()));
- // If we don't have a validated contact match, just use the
- // entry as it existed before.
- if (entry == null && !isPhoneQuery()) {
- entry = temp.getEntry();
- }
- final RecipientEntry tempEntry = entry;
- if (tempEntry != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- replaceChip(temp, tempEntry);
+ RecipientAlternatesAdapter.getMatchingRecipients(getContext(), addresses,
+ ((BaseRecipientAdapter) getAdapter()).getAccount(),
+ new RecipientMatchCallback() {
+
+ @Override
+ public void matchesFound(Map<String, RecipientEntry> entries) {
+ for (final DrawableRecipientChip temp : originalRecipients) {
+ if (RecipientEntry.isCreatedRecipient(temp.getEntry()
+ .getContactId())
+ && getSpannable().getSpanStart(temp) != -1) {
+ // Replace this.
+ RecipientEntry entry = createValidatedEntry(entries
+ .get(tokenizeAddress(temp.getEntry().getDestination())
+ .toLowerCase()));
+ // If we don't have a validated contact
+ // match, just use the
+ // entry as it existed before.
+ if (entry == null && !isPhoneQuery()) {
+ entry = temp.getEntry();
+ }
+ final RecipientEntry tempEntry = entry;
+ if (tempEntry != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ replaceChip(temp, tempEntry);
+ }
+ });
+ }
+ }
}
- });
- }
- }
- }
+ }
+
+ @Override
+ public void matchesNotFound(final Set<String> unfoundAddresses) {
+ // No action required
+ }
+ });
return null;
}
}
@@ -2546,7 +2695,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
float x = event.getX();
float y = event.getY();
int offset = putOffsetInRange(getOffsetForPosition(x, y));
- RecipientChip currentChip = findChip(offset);
+ DrawableRecipientChip currentChip = findChip(offset);
if (currentChip != null) {
if (mDragEnabled) {
// Start drag-and-drop for the selected chip.
@@ -2568,7 +2717,7 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
/**
* Starts drag-and-drop for the selected chip.
*/
- private void startDrag(RecipientChip currentChip) {
+ private void startDrag(DrawableRecipientChip currentChip) {
String address = currentChip.getEntry().getDestination();
ClipData data = ClipData.newPlainText(address, address + COMMIT_CHAR_COMMA);
@@ -2603,22 +2752,22 @@ public class RecipientEditTextView extends MultiAutoCompleteTextView implements
* Drag shadow for a {@link RecipientChip}.
*/
private final class RecipientChipShadow extends DragShadowBuilder {
- private final RecipientChip mChip;
+ private final DrawableRecipientChip mChip;
- public RecipientChipShadow(RecipientChip chip) {
+ public RecipientChipShadow(DrawableRecipientChip chip) {
mChip = chip;
}
@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
- Rect rect = mChip.getDrawable().getBounds();
+ Rect rect = mChip.getBounds();
shadowSize.set(rect.width(), rect.height());
shadowTouchPoint.set(rect.centerX(), rect.centerY());
}
@Override
public void onDrawShadow(Canvas canvas) {
- mChip.getDrawable().draw(canvas);
+ mChip.draw(canvas);
}
}
diff --git a/chips/src/com/android/ex/chips/RecipientEntry.java b/chips/src/com/android/ex/chips/RecipientEntry.java
index 0448229..44bc767 100644
--- a/chips/src/com/android/ex/chips/RecipientEntry.java
+++ b/chips/src/com/android/ex/chips/RecipientEntry.java
@@ -19,6 +19,8 @@ package com.android.ex.chips;
import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.DisplayNameSources;
+import android.text.util.Rfc822Token;
+import android.text.util.Rfc822Tokenizer;
/**
* Represents one entry inside recipient auto-complete list.
@@ -65,29 +67,16 @@ public class RecipientEntry {
private final Uri mPhotoThumbnailUri;
+ private boolean mIsValid;
/**
* This can be updated after this object being constructed, when the photo is fetched
* from remote directories.
*/
private byte[] mPhotoBytes;
- private RecipientEntry(int entryType) {
- mEntryType = entryType;
- mDisplayName = null;
- mDestination = null;
- mDestinationType = INVALID_DESTINATION_TYPE;
- mDestinationLabel = null;
- mContactId = -1;
- mDataId = -1;
- mPhotoThumbnailUri = null;
- mPhotoBytes = null;
- mIsDivider = true;
- }
-
- private RecipientEntry(
- int entryType, String displayName,
- String destination, int destinationType, String destinationLabel,
- long contactId, long dataId, Uri photoThumbnailUri, boolean isFirstLevel) {
+ private RecipientEntry(int entryType, String displayName, String destination,
+ int destinationType, String destinationLabel, long contactId, long dataId,
+ Uri photoThumbnailUri, boolean isFirstLevel, boolean isValid) {
mEntryType = entryType;
mIsFirstLevel = isFirstLevel;
mDisplayName = displayName;
@@ -99,6 +88,11 @@ public class RecipientEntry {
mPhotoThumbnailUri = photoThumbnailUri;
mPhotoBytes = null;
mIsDivider = false;
+ mIsValid = isValid;
+ }
+
+ public boolean isValid() {
+ return mIsValid;
}
/**
@@ -114,10 +108,23 @@ public class RecipientEntry {
* This address has not been resolved to a contact and therefore does not
* have a contact id or photo.
*/
- public static RecipientEntry constructFakeEntry(String address) {
- return new RecipientEntry(ENTRY_TYPE_PERSON, address, address,
+ public static RecipientEntry constructFakeEntry(final String address, final boolean isValid) {
+ final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(address);
+ final String tokenizedAddress = tokens.length > 0 ? tokens[0].getAddress() : address;
+
+ return new RecipientEntry(ENTRY_TYPE_PERSON, tokenizedAddress, tokenizedAddress,
+ INVALID_DESTINATION_TYPE, null,
+ INVALID_CONTACT, INVALID_CONTACT, null, true, isValid);
+ }
+
+ /**
+ * Construct a RecipientEntry from just a phone number.
+ */
+ public static RecipientEntry constructFakePhoneEntry(final String phoneNumber,
+ final boolean isValid) {
+ return new RecipientEntry(ENTRY_TYPE_PERSON, phoneNumber, phoneNumber,
INVALID_DESTINATION_TYPE, null,
- INVALID_CONTACT, INVALID_CONTACT, null, true);
+ INVALID_CONTACT, INVALID_CONTACT, null, true, isValid);
}
/**
@@ -136,41 +143,37 @@ public class RecipientEntry {
* with both an associated display name. This address has not been resolved
* to a contact and therefore does not have a contact id or photo.
*/
- public static RecipientEntry constructGeneratedEntry(String display, String address) {
- return new RecipientEntry(ENTRY_TYPE_PERSON, display,
- address, INVALID_DESTINATION_TYPE, null,
- GENERATED_CONTACT, GENERATED_CONTACT, null, true);
- }
-
- public static RecipientEntry constructTopLevelEntry(
- String displayName, int displayNameSource, String destination, int destinationType,
- String destinationLabel, long contactId, long dataId, Uri photoThumbnailUri) {
- return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource, displayName,
- destination),
- destination, destinationType, destinationLabel,
- contactId, dataId,
- photoThumbnailUri, true);
- }
-
- public static RecipientEntry constructTopLevelEntry(
- String displayName, int displayNameSource, String destination, int destinationType,
- String destinationLabel, long contactId, long dataId,
- String thumbnailUriAsString) {
- return new RecipientEntry(
- ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource, displayName, destination),
- destination, destinationType, destinationLabel,
- contactId, dataId,
- (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString) : null), true);
- }
-
- public static RecipientEntry constructSecondLevelEntry(
- String displayName, int displayNameSource, String destination, int destinationType,
- String destinationLabel, long contactId, long dataId, String thumbnailUriAsString) {
- return new RecipientEntry(
- ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource, displayName, destination),
- destination, destinationType, destinationLabel,
- contactId, dataId,
- (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString) : null), false);
+ public static RecipientEntry constructGeneratedEntry(String display, String address,
+ boolean isValid) {
+ return new RecipientEntry(ENTRY_TYPE_PERSON, display, address, INVALID_DESTINATION_TYPE,
+ null, GENERATED_CONTACT, GENERATED_CONTACT, null, true, isValid);
+ }
+
+ public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
+ String destination, int destinationType, String destinationLabel, long contactId,
+ long dataId, Uri photoThumbnailUri, boolean isValid) {
+ return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
+ displayName, destination), destination, destinationType, destinationLabel,
+ contactId, dataId, photoThumbnailUri, true, isValid);
+ }
+
+ public static RecipientEntry constructTopLevelEntry(String displayName, int displayNameSource,
+ String destination, int destinationType, String destinationLabel, long contactId,
+ long dataId, String thumbnailUriAsString, boolean isValid) {
+ return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
+ displayName, destination), destination, destinationType, destinationLabel,
+ contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString)
+ : null), true, isValid);
+ }
+
+ public static RecipientEntry constructSecondLevelEntry(String displayName,
+ int displayNameSource, String destination, int destinationType,
+ String destinationLabel, long contactId, long dataId, String thumbnailUriAsString,
+ boolean isValid) {
+ return new RecipientEntry(ENTRY_TYPE_PERSON, pickDisplayName(displayNameSource,
+ displayName, destination), destination, destinationType, destinationLabel,
+ contactId, dataId, (thumbnailUriAsString != null ? Uri.parse(thumbnailUriAsString)
+ : null), false, isValid);
}
public int getEntryType() {
@@ -226,4 +229,9 @@ public class RecipientEntry {
public boolean isSelectable() {
return mEntryType == ENTRY_TYPE_PERSON;
}
+
+ @Override
+ public String toString() {
+ return mDisplayName + " <" + mDestination + ">, isValid=" + mIsValid;
+ }
} \ No newline at end of file
diff --git a/chips/src/com/android/ex/chips/SingleRecipientArrayAdapter.java b/chips/src/com/android/ex/chips/SingleRecipientArrayAdapter.java
index 8131fc3..0571a4e 100644
--- a/chips/src/com/android/ex/chips/SingleRecipientArrayAdapter.java
+++ b/chips/src/com/android/ex/chips/SingleRecipientArrayAdapter.java
@@ -43,7 +43,7 @@ class SingleRecipientArrayAdapter extends ArrayAdapter<RecipientEntry> {
if (convertView == null) {
convertView = newView();
}
- bindView(convertView, convertView.getContext(), getItem(position));
+ bindView(convertView, getItem(position));
return convertView;
}
@@ -51,7 +51,7 @@ class SingleRecipientArrayAdapter extends ArrayAdapter<RecipientEntry> {
return mLayoutInflater.inflate(mLayoutId, null);
}
- private void bindView(View view, Context context, RecipientEntry entry) {
+ private static void bindView(View view, RecipientEntry entry) {
TextView display = (TextView) view.findViewById(android.R.id.title);
ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
display.setText(entry.getDisplayName());
diff --git a/chips/src/com/android/ex/chips/recipientchip/BaseRecipientChip.java b/chips/src/com/android/ex/chips/recipientchip/BaseRecipientChip.java
new file mode 100644
index 0000000..a080ee7
--- /dev/null
+++ b/chips/src/com/android/ex/chips/recipientchip/BaseRecipientChip.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ex.chips.recipientchip;
+
+import com.android.ex.chips.RecipientEntry;
+
+/**
+ * BaseRecipientChip defines an object that contains information relevant to a
+ * particular recipient.
+ */
+interface BaseRecipientChip {
+
+ /**
+ * Set the selected state of the chip.
+ */
+ void setSelected(boolean selected);
+
+ /**
+ * Return true if the chip is selected.
+ */
+ boolean isSelected();
+
+ /**
+ * Get the text displayed in the chip.
+ */
+ CharSequence getDisplay();
+
+ /**
+ * Get the text value this chip represents.
+ */
+ CharSequence getValue();
+
+ /**
+ * Get the id of the contact associated with this chip.
+ */
+ long getContactId();
+
+ /**
+ * Get the id of the data associated with this chip.
+ */
+ long getDataId();
+
+ /**
+ * Get associated RecipientEntry.
+ */
+ RecipientEntry getEntry();
+
+ /**
+ * Set the text in the edittextview originally associated with this chip
+ * before any reverse lookups.
+ */
+ void setOriginalText(String text);
+
+ /**
+ * Set the text in the edittextview originally associated with this chip
+ * before any reverse lookups.
+ */
+ CharSequence getOriginalText();
+}
diff --git a/chips/src/com/android/ex/chips/recipientchip/DrawableRecipientChip.java b/chips/src/com/android/ex/chips/recipientchip/DrawableRecipientChip.java
new file mode 100644
index 0000000..396a8ac
--- /dev/null
+++ b/chips/src/com/android/ex/chips/recipientchip/DrawableRecipientChip.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ex.chips.recipientchip;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+/**
+ * RecipientChip defines a drawable object that contains information relevant to a
+ * particular recipient.
+ */
+public interface DrawableRecipientChip extends BaseRecipientChip {
+ /**
+ * Get the bounds of the chip; may be 0,0 if it is not visibly rendered.
+ */
+ Rect getBounds();
+
+ /**
+ * Draw the chip.
+ */
+ void draw(Canvas canvas);
+}
diff --git a/chips/src/com/android/ex/chips/recipientchip/InvisibleRecipientChip.java b/chips/src/com/android/ex/chips/recipientchip/InvisibleRecipientChip.java
new file mode 100644
index 0000000..0380a81
--- /dev/null
+++ b/chips/src/com/android/ex/chips/recipientchip/InvisibleRecipientChip.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ex.chips.recipientchip;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.text.style.ReplacementSpan;
+
+import com.android.ex.chips.RecipientEntry;
+
+/**
+ * RecipientChip defines a span that contains information relevant to a
+ * particular recipient.
+ */
+public class InvisibleRecipientChip extends ReplacementSpan implements DrawableRecipientChip {
+ private final SimpleRecipientChip mDelegate;
+
+ public InvisibleRecipientChip(final RecipientEntry entry) {
+ super();
+
+ mDelegate = new SimpleRecipientChip(entry);
+ }
+
+ @Override
+ public void setSelected(final boolean selected) {
+ mDelegate.setSelected(selected);
+ }
+
+ @Override
+ public boolean isSelected() {
+ return mDelegate.isSelected();
+ }
+
+ @Override
+ public CharSequence getDisplay() {
+ return mDelegate.getDisplay();
+ }
+
+ @Override
+ public CharSequence getValue() {
+ return mDelegate.getValue();
+ }
+
+ @Override
+ public long getContactId() {
+ return mDelegate.getContactId();
+ }
+
+ @Override
+ public long getDataId() {
+ return mDelegate.getDataId();
+ }
+
+ @Override
+ public RecipientEntry getEntry() {
+ return mDelegate.getEntry();
+ }
+
+ @Override
+ public void setOriginalText(final String text) {
+ mDelegate.setOriginalText(text);
+ }
+
+ @Override
+ public CharSequence getOriginalText() {
+ return mDelegate.getOriginalText();
+ }
+
+ @Override
+ public void draw(final Canvas canvas, final CharSequence text, final int start, final int end,
+ final float x, final int top, final int y, final int bottom, final Paint paint) {
+ // Do nothing.
+ }
+
+ @Override
+ public int getSize(final Paint paint, final CharSequence text, final int start, final int end,
+ final Paint.FontMetricsInt fm) {
+ return 0;
+ }
+
+ @Override
+ public Rect getBounds() {
+ return new Rect(0, 0, 0, 0);
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ // do nothing.
+ }
+}
diff --git a/chips/src/com/android/ex/chips/RecipientChip.java b/chips/src/com/android/ex/chips/recipientchip/SimpleRecipientChip.java
index 0f93a0d..c04b3be 100644
--- a/chips/src/com/android/ex/chips/RecipientChip.java
+++ b/chips/src/com/android/ex/chips/recipientchip/SimpleRecipientChip.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -14,18 +14,13 @@
* limitations under the License.
*/
-package com.android.ex.chips;
+package com.android.ex.chips.recipientchip;
+
+import com.android.ex.chips.RecipientEntry;
-import android.graphics.drawable.Drawable;
import android.text.TextUtils;
-import android.text.style.DynamicDrawableSpan;
-import android.text.style.ImageSpan;
-/**
- * RecipientChip defines an ImageSpan that contains information relevant to a
- * particular recipient.
- */
-/* package */class RecipientChip extends ImageSpan {
+class SimpleRecipientChip implements BaseRecipientChip {
private final CharSequence mDisplay;
private final CharSequence mValue;
@@ -34,14 +29,13 @@ import android.text.style.ImageSpan;
private final long mDataId;
- private RecipientEntry mEntry;
+ private final RecipientEntry mEntry;
private boolean mSelected = false;
private CharSequence mOriginalText;
- public RecipientChip(Drawable drawable, RecipientEntry entry, int offset) {
- super(drawable, DynamicDrawableSpan.ALIGN_BOTTOM);
+ public SimpleRecipientChip(final RecipientEntry entry) {
mDisplay = entry.getDisplayName();
mValue = entry.getDestination().trim();
mContactId = entry.getContactId();
@@ -49,64 +43,57 @@ import android.text.style.ImageSpan;
mEntry = entry;
}
- /**
- * Set the selected state of the chip.
- * @param selected
- */
- public void setSelected(boolean selected) {
+ @Override
+ public void setSelected(final boolean selected) {
mSelected = selected;
}
- /**
- * Return true if the chip is selected.
- */
+ @Override
public boolean isSelected() {
return mSelected;
}
- /**
- * Get the text displayed in the chip.
- */
+ @Override
public CharSequence getDisplay() {
return mDisplay;
}
- /**
- * Get the text value this chip represents.
- */
+ @Override
public CharSequence getValue() {
return mValue;
}
- /**
- * Get the id of the contact associated with this chip.
- */
+ @Override
public long getContactId() {
return mContactId;
}
- /**
- * Get the id of the data associated with this chip.
- */
+ @Override
public long getDataId() {
return mDataId;
}
- /**
- * Get associated RecipientEntry.
- */
+ @Override
public RecipientEntry getEntry() {
return mEntry;
}
- public void setOriginalText(String text) {
- if (!TextUtils.isEmpty(text)) {
- text = text.trim();
+ @Override
+ public void setOriginalText(final String text) {
+ if (TextUtils.isEmpty(text)) {
+ mOriginalText = text;
+ } else {
+ mOriginalText = text.trim();
}
- mOriginalText = text;
}
+ @Override
public CharSequence getOriginalText() {
return !TextUtils.isEmpty(mOriginalText) ? mOriginalText : mEntry.getDestination();
}
-}
+
+ @Override
+ public String toString() {
+ return mDisplay + " <" + mValue + ">";
+ }
+} \ No newline at end of file
diff --git a/chips/src/com/android/ex/chips/recipientchip/VisibleRecipientChip.java b/chips/src/com/android/ex/chips/recipientchip/VisibleRecipientChip.java
new file mode 100644
index 0000000..acade7f
--- /dev/null
+++ b/chips/src/com/android/ex/chips/recipientchip/VisibleRecipientChip.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ex.chips.recipientchip;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.text.style.DynamicDrawableSpan;
+import android.text.style.ImageSpan;
+
+import com.android.ex.chips.RecipientEntry;
+
+/**
+ * VisibleRecipientChip defines an ImageSpan that contains information relevant to a
+ * particular recipient and renders a background asset to go with it.
+ */
+public class VisibleRecipientChip extends ImageSpan implements DrawableRecipientChip {
+ private final SimpleRecipientChip mDelegate;
+
+ public VisibleRecipientChip(final Drawable drawable, final RecipientEntry entry) {
+ super(drawable, DynamicDrawableSpan.ALIGN_BOTTOM);
+
+ mDelegate = new SimpleRecipientChip(entry);
+ }
+
+ @Override
+ public void setSelected(final boolean selected) {
+ mDelegate.setSelected(selected);
+ }
+
+ @Override
+ public boolean isSelected() {
+ return mDelegate.isSelected();
+ }
+
+ @Override
+ public CharSequence getDisplay() {
+ return mDelegate.getDisplay();
+ }
+
+ @Override
+ public CharSequence getValue() {
+ return mDelegate.getValue();
+ }
+
+ @Override
+ public long getContactId() {
+ return mDelegate.getContactId();
+ }
+
+ @Override
+ public long getDataId() {
+ return mDelegate.getDataId();
+ }
+
+ @Override
+ public RecipientEntry getEntry() {
+ return mDelegate.getEntry();
+ }
+
+ @Override
+ public void setOriginalText(final String text) {
+ mDelegate.setOriginalText(text);
+ }
+
+ @Override
+ public CharSequence getOriginalText() {
+ return mDelegate.getOriginalText();
+ }
+
+ @Override
+ public Rect getBounds() {
+ return getDrawable().getBounds();
+ }
+
+ @Override
+ public void draw(final Canvas canvas) {
+ getDrawable().draw(canvas);
+ }
+
+ @Override
+ public String toString() {
+ return mDelegate.toString();
+ }
+}
diff --git a/chips/tests/Android.mk b/chips/tests/Android.mk
index 313af7d..b01aa0c 100644
--- a/chips/tests/Android.mk
+++ b/chips/tests/Android.mk
@@ -20,7 +20,6 @@ LOCAL_PACKAGE_NAME := ChipsTests
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES += android-common-chips
LOCAL_RESOURCE_DIR := frameworks/ex/chips/res/
LOCAL_AAPT_FLAGS := --auto-add-overlay
diff --git a/chips/tests/src/com/android/ex/chips/ChipsTest.java b/chips/tests/src/com/android/ex/chips/ChipsTest.java
index 6639bcb..7963086 100644
--- a/chips/tests/src/com/android/ex/chips/ChipsTest.java
+++ b/chips/tests/src/com/android/ex/chips/ChipsTest.java
@@ -28,12 +28,17 @@ import android.text.style.ImageSpan;
import android.text.util.Rfc822Tokenizer;
import android.widget.TextView;
+import com.android.ex.chips.BaseRecipientAdapter;
import com.android.ex.chips.RecipientEditTextView;
import com.android.ex.chips.RecipientEntry;
+import com.android.ex.chips.recipientchip.DrawableRecipientChip;
+import com.android.ex.chips.recipientchip.VisibleRecipientChip;;
+
+import java.util.regex.Pattern;
@SmallTest
public class ChipsTest extends AndroidTestCase {
- private RecipientChip[] mMockRecips;
+ private DrawableRecipientChip[] mMockRecips;
private RecipientEntry[] mMockEntries;
@@ -50,7 +55,7 @@ public class ChipsTest extends AndroidTestCase {
}
@Override
- public RecipientChip[] getSortedRecipients() {
+ public DrawableRecipientChip[] getSortedRecipients() {
return mMockRecips;
}
@@ -79,7 +84,7 @@ public class ChipsTest extends AndroidTestCase {
}
@Override
- public RecipientChip[] getSortedRecipients() {
+ public DrawableRecipientChip[] getSortedRecipients() {
return mMockRecips;
}
@@ -120,9 +125,14 @@ public class ChipsTest extends AndroidTestCase {
}
private class TestBaseRecipientAdapter extends BaseRecipientAdapter {
- public TestBaseRecipientAdapter(Context context) {
+ public TestBaseRecipientAdapter(final Context context) {
super(context);
}
+
+ public TestBaseRecipientAdapter(final Context context, final int preferredMaxResultCount,
+ final int queryMode) {
+ super(context, preferredMaxResultCount, queryMode);
+ }
}
private MockRecipientEditTextView createViewForTesting() {
@@ -135,15 +145,15 @@ public class ChipsTest extends AndroidTestCase {
public void testCreateDisplayText() {
RecipientEditTextView view = createViewForTesting();
RecipientEntry entry = RecipientEntry.constructGeneratedEntry("User Name, Jr",
- "user@username.com");
+ "user@username.com", true);
String testAddress = view.createAddressText(entry);
String testDisplay = view.createChipDisplayText(entry);
assertEquals("Expected a properly formatted RFC email address",
"\"User Name, Jr\" <user@username.com>, ", testAddress);
assertEquals("Expected a displayable name", "User Name, Jr", testDisplay);
-
- RecipientEntry alreadyFormatted = RecipientEntry.constructFakeEntry("user@username.com, ");
+ RecipientEntry alreadyFormatted =
+ RecipientEntry.constructFakeEntry("user@username.com, ", true);
testAddress = view.createAddressText(alreadyFormatted);
testDisplay = view.createChipDisplayText(alreadyFormatted);
assertEquals("Expected a properly formatted RFC email address", "<user@username.com>, ",
@@ -151,13 +161,13 @@ public class ChipsTest extends AndroidTestCase {
assertEquals("Expected a displayable name", "user@username.com", testDisplay);
RecipientEntry alreadyFormattedNoSpace = RecipientEntry
- .constructFakeEntry("user@username.com,");
+ .constructFakeEntry("user@username.com,", true);
testAddress = view.createAddressText(alreadyFormattedNoSpace);
assertEquals("Expected a properly formatted RFC email address", "<user@username.com>, ",
testAddress);
RecipientEntry alreadyNamed = RecipientEntry.constructGeneratedEntry("User Name",
- "\"User Name, Jr\" <user@username.com>");
+ "\"User Name, Jr\" <user@username.com>", true);
testAddress = view.createAddressText(alreadyNamed);
testDisplay = view.createChipDisplayText(alreadyNamed);
assertEquals(
@@ -254,8 +264,8 @@ public class ChipsTest extends AndroidTestCase {
String first = (String) mTokenizer.terminateToken("FIRST");
String second = (String) mTokenizer.terminateToken("SECOND");
String third = (String) mTokenizer.terminateToken("THIRD");
- String fourth = (String) ("FOURTH,");
- String fifth = (String) ("FIFTH,");
+ String fourth = "FOURTH,";
+ String fifth = "FIFTH,";
mEditable = new SpannableStringBuilder();
mEditable.append(first+second+third+fourth+fifth);
assertEquals(view.countTokens(mEditable), 5);
@@ -620,7 +630,7 @@ public class ChipsTest extends AndroidTestCase {
mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
assertEquals(mEditable.toString(), first + second + third);
view.replaceChip(mMockRecips[mMockRecips.length - 3], RecipientEntry
- .constructGeneratedEntry("replacement", "replacement@replacement.com"));
+ .constructGeneratedEntry("replacement", "replacement@replacement.com", true));
assertEquals(mEditable.toString(), mTokenizer
.terminateToken("replacement <replacement@replacement.com>")
+ second + third);
@@ -636,10 +646,11 @@ public class ChipsTest extends AndroidTestCase {
assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), mEditable
.toString().indexOf(third)
+ third.trim().length());
- RecipientChip[] spans = mEditable.getSpans(0, mEditable.length(), RecipientChip.class);
+ DrawableRecipientChip[] spans =
+ mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class);
assertEquals(spans.length, 3);
spans = mEditable
- .getSpans(0, mEditable.toString().indexOf(second) - 1, RecipientChip.class);
+ .getSpans(0, mEditable.toString().indexOf(second) - 1, DrawableRecipientChip.class);
assertEquals((String) spans[0].getDisplay(), "replacement");
@@ -657,7 +668,7 @@ public class ChipsTest extends AndroidTestCase {
mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
assertEquals(mEditable.toString(), first + second + third);
view.replaceChip(mMockRecips[mMockRecips.length - 2], RecipientEntry
- .constructGeneratedEntry("replacement", "replacement@replacement.com"));
+ .constructGeneratedEntry("replacement", "replacement@replacement.com", true));
assertEquals(mEditable.toString(), first + mTokenizer
.terminateToken("replacement <replacement@replacement.com>") + third);
assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
@@ -669,10 +680,10 @@ public class ChipsTest extends AndroidTestCase {
assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), mEditable
.toString().indexOf(third)
+ third.trim().length());
- spans = mEditable.getSpans(0, mEditable.length(), RecipientChip.class);
+ spans = mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class);
assertEquals(spans.length, 3);
- spans = mEditable
- .getSpans(firstEnd, mEditable.toString().indexOf(third) - 1, RecipientChip.class);
+ spans = mEditable.getSpans(firstEnd, mEditable.toString().indexOf(third) - 1,
+ DrawableRecipientChip.class);
assertEquals((String) spans[0].getDisplay(), "replacement");
@@ -690,7 +701,7 @@ public class ChipsTest extends AndroidTestCase {
mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
assertEquals(mEditable.toString(), first + second + third);
view.replaceChip(mMockRecips[mMockRecips.length - 1], RecipientEntry
- .constructGeneratedEntry("replacement", "replacement@replacement.com"));
+ .constructGeneratedEntry("replacement", "replacement@replacement.com", true));
assertEquals(mEditable.toString(), first + second + mTokenizer
.terminateToken("replacement <replacement@replacement.com>"));
assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
@@ -699,10 +710,10 @@ public class ChipsTest extends AndroidTestCase {
assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), secondEnd);
assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), -1);
assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), -1);
- spans = mEditable.getSpans(0, mEditable.length(), RecipientChip.class);
+ spans = mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class);
assertEquals(spans.length, 3);
spans = mEditable
- .getSpans(secondEnd, mEditable.length(), RecipientChip.class);
+ .getSpans(secondEnd, mEditable.length(), DrawableRecipientChip.class);
assertEquals((String) spans[0].getDisplay(), "replacement");
}
@@ -717,7 +728,7 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append("user@user.com");
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length, 0);
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 0);
assertEquals(mEditable.toString(), "user@user.com");
// Test adding a single address to an empty chips field with a space at
@@ -727,7 +738,7 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append(tokenizedUser);
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length, 0);
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 0);
assertEquals(mEditable.toString(), tokenizedUser);
// Test adding a single address to an empty chips field with a semicolon at
@@ -737,7 +748,7 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append(tokenizedUser);
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length, 1);
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 1);
// Test adding 2 address to an empty chips field. The second to last
// address should become a chip and the last address should stay as
@@ -746,9 +757,9 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append("user1,user2@user.com");
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length, 1);
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 1);
assertEquals(mEditable.getSpans(0, mEditable.toString().indexOf("user2@user.com"),
- RecipientChip.class).length, 1);
+ DrawableRecipientChip.class).length, 1);
assertEquals(mEditable.toString(), "<user1>, user2@user.com");
// Test adding a single address to the end of existing chips. The existing
@@ -773,7 +784,7 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append("user@user.com");
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length,
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length,
mMockRecips.length);
assertEquals(mEditable.toString(), first + second + third + "user@user.com");
@@ -790,12 +801,12 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append("user1, user2@user.com");
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length,
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length,
mMockRecips.length + 1);
assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable
- .toString().indexOf("user2@user.com") - 1, RecipientChip.class).length, 1);
+ .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1);
assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable
- .length(), RecipientChip.class).length, 0);
+ .length(), DrawableRecipientChip.class).length, 0);
assertEquals(mEditable.toString(), first + second + third + "<user1>, user2@user.com");
// Paste 2 addresses after existing chips. We expect the first address to be turned into
@@ -812,12 +823,12 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append("user1,user2@user.com");
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length,
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length,
mMockRecips.length + 1);
assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable
- .toString().indexOf("user2@user.com") - 1, RecipientChip.class).length, 1);
+ .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1);
assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable
- .length(), RecipientChip.class).length, 0);
+ .length(), DrawableRecipientChip.class).length, 0);
assertEquals(mEditable.toString(), first + second + third + "<user1>, user2@user.com");
// Test a complete token pasted in at the end. It should be turned into a chip.
@@ -825,11 +836,11 @@ public class ChipsTest extends AndroidTestCase {
mEditable.append("user1, user2@user.com,");
view.setSelection(mEditable.length());
view.handlePaste();
- assertEquals(mEditable.getSpans(0, mEditable.length(), RecipientChip.class).length, 2);
+ assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 2);
assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable
- .toString().indexOf("user2@user.com") - 1, RecipientChip.class).length, 1);
+ .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1);
assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable
- .length(), RecipientChip.class).length, 1);
+ .length(), DrawableRecipientChip.class).length, 1);
assertEquals(mEditable.toString(), "<user1>, <user2@user.com>, ");
}
@@ -922,11 +933,96 @@ public class ChipsTest extends AndroidTestCase {
mMockEntries = new RecipientEntry[size];
for (int i = 0; i < size; i++) {
mMockEntries[i] = RecipientEntry.constructGeneratedEntry("user",
- "user@username.com");
+ "user@username.com", true);
}
- mMockRecips = new RecipientChip[size];
+ mMockRecips = new DrawableRecipientChip[size];
for (int i = 0; i < size; i++) {
- mMockRecips[i] = new RecipientChip(null, mMockEntries[i], i);
+ mMockRecips[i] = new VisibleRecipientChip(null, mMockEntries[i]);
}
}
+
+ /**
+ * <p>
+ * Ensure the original text is always accurate, regardless of the type of email. The original
+ * text is used to determine where to display the chip span. If this test fails, it means some
+ * text that should be turned into one whole chip may behave unexpectedly.
+ * </p>
+ * <p>
+ * For example, a bug was seen where
+ *
+ * <pre>
+ * "Android User" <android@example.com>
+ * </pre>
+ *
+ * was converted to
+ *
+ * <pre>
+ * Android User [android@example.com]
+ * </pre>
+ *
+ * where text inside [] is a chip.
+ * </p>
+ */
+ public void testCreateReplacementChipOriginalText() {
+ // Name in quotes + email address
+ testCreateReplacementChipOriginalText("\"Android User\" <android@example.com>,");
+ // Name in quotes + email address without brackets
+ testCreateReplacementChipOriginalText("\"Android User\" android@example.com,");
+ // Name in quotes
+ testCreateReplacementChipOriginalText("\"Android User\",");
+ // Name without quotes + email address
+ testCreateReplacementChipOriginalText("Android User <android@example.com>,");
+ // Name without quotes
+ testCreateReplacementChipOriginalText("Android User,");
+ // Email address
+ testCreateReplacementChipOriginalText("<android@example.com>,");
+ // Email address without brackets
+ testCreateReplacementChipOriginalText("android@example.com,");
+ }
+
+ private void testCreateReplacementChipOriginalText(final String email) {
+ // No trailing space
+ attemptCreateReplacementChipOriginalText(email.trim());
+ // Trailing space
+ attemptCreateReplacementChipOriginalText(email.trim() + " ");
+ }
+
+ private void attemptCreateReplacementChipOriginalText(final String email) {
+ final RecipientEditTextView view = new RecipientEditTextView(getContext(), null);
+
+ view.setText(email);
+ view.mPendingChips.add(email);
+
+ view.createReplacementChip(0, email.length(), view.getText(), true);
+ // The "original text" should be the email without the comma or space(s)
+ assertEquals(email.replaceAll(",\\s*$", ""),
+ view.mTemporaryRecipients.get(0).getOriginalText().toString().trim());
+ }
+
+ public void testCreateTokenizedEntryForPhone() {
+ final String phonePattern = "[^\\d]*888[^\\d]*555[^\\d]*1234[^\\d]*";
+ final String phone1 = "8885551234";
+ final String phone2 = "888-555-1234";
+ final String phone3 = "(888) 555-1234";
+
+ final RecipientEditTextView view = new RecipientEditTextView(getContext(), null);
+ final BaseRecipientAdapter adapter = new TestBaseRecipientAdapter(getContext(), 10,
+ BaseRecipientAdapter.QUERY_TYPE_PHONE);
+ view.setAdapter(adapter);
+
+ final RecipientEntry entry1 = view.createTokenizedEntry(phone1);
+ final String destination1 = entry1.getDestination();
+ assertTrue(phone1 + " failed with " + destination1,
+ Pattern.matches(phonePattern, destination1));
+
+ final RecipientEntry entry2 = view.createTokenizedEntry(phone2);
+ final String destination2 = entry2.getDestination();
+ assertTrue(phone2 + " failed with " + destination2,
+ Pattern.matches(phonePattern, destination2));
+
+ final RecipientEntry entry3 = view.createTokenizedEntry(phone3);
+ final String destination3 = entry3.getDestination();
+ assertTrue(phone3 + " failed with " + destination3,
+ Pattern.matches(phonePattern, destination3));
+ }
}
diff --git a/chips/tests/src/com/android/ex/chips/RecipientAlternatesAdapterTest.java b/chips/tests/src/com/android/ex/chips/RecipientAlternatesAdapterTest.java
index f4b87c0..a1a1c7a 100644
--- a/chips/tests/src/com/android/ex/chips/RecipientAlternatesAdapterTest.java
+++ b/chips/tests/src/com/android/ex/chips/RecipientAlternatesAdapterTest.java
@@ -18,8 +18,13 @@ package com.android.ex.chips;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.net.Uri;
+import android.provider.ContactsContract.DisplayNameSources;
import android.test.AndroidTestCase;
+import com.android.ex.chips.RecipientAlternatesAdapter;
+import com.android.ex.chips.RecipientEntry;
+
public class RecipientAlternatesAdapterTest extends AndroidTestCase {
public void testRemoveDuplicateDestinations() {
@@ -99,4 +104,55 @@ public class RecipientAlternatesAdapterTest extends AndroidTestCase {
assertEquals(photoUri, c.getString(6));
assertEquals(displayNameSource, c.getInt(7));
}
+
+ public void testGetBetterRecipient() {
+ // Ensure that if either (but not both) parameters are null, the other is returned
+ {
+ final RecipientEntry entry1 =
+ RecipientEntry.constructFakeEntry("1@android.com", true);
+ final RecipientEntry entry2 = null;
+
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry1, entry2), entry1);
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry2, entry1), entry1);
+ }
+
+ // Ensure that if only one has a display name, it is used
+ {
+ final RecipientEntry entry1 =
+ RecipientEntry.constructTopLevelEntry("Android", DisplayNameSources.NICKNAME,
+ "1@android.com", 0, null, 0, 0, (Uri) null, true);
+ final RecipientEntry entry2 = RecipientEntry.constructFakeEntry("1@android.com", true);
+
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry1, entry2), entry1);
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry2, entry1), entry1);
+ }
+
+ // Ensure that if one has a display name different from its destination, and the other's
+ // is equal to its destination, we use the unique one
+ {
+ final RecipientEntry entry1 =
+ RecipientEntry.constructTopLevelEntry("Android", DisplayNameSources.NICKNAME,
+ "1@android.com", 0, null, 0, 0, (Uri) null, true);
+ final RecipientEntry entry2 =
+ RecipientEntry.constructTopLevelEntry("2@android.com", DisplayNameSources.EMAIL,
+ "2@android.com", 0, null, 0, 0, (Uri) null, true);
+
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry1, entry2), entry1);
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry2, entry1), entry1);
+ }
+
+ // Ensure that if only one has a photo, it is used
+ {
+ final RecipientEntry entry1 =
+ RecipientEntry.constructTopLevelEntry("Android", DisplayNameSources.NICKNAME,
+ "1@android.com", 0, null, 0, 0, Uri.parse("http://www.android.com"),
+ true);
+ final RecipientEntry entry2 =
+ RecipientEntry.constructTopLevelEntry("Android", DisplayNameSources.EMAIL,
+ "2@android.com", 0, null, 0, 0, (Uri) null, true);
+
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry1, entry2), entry1);
+ assertEquals(RecipientAlternatesAdapter.getBetterRecipient(entry2, entry1), entry1);
+ }
+ }
}
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/photoviewer/Android.mk b/photoviewer/Android.mk
deleted file mode 100644
index 54ad563..0000000
--- a/photoviewer/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2012 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android-common-photoviewer
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
-
-LOCAL_SDK_VERSION := 16
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-logtags-files-under, src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-##################################################
-# Build all sub-directories
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/photoviewer/AndroidManifest.xml b/photoviewer/AndroidManifest.xml
deleted file mode 100644
index 485e044..0000000
--- a/photoviewer/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.photo"
- android:versionCode="1">
-</manifest> \ No newline at end of file
diff --git a/photoviewer/res/drawable-hdpi/actionbar_translucent.9.png b/photoviewer/res/drawable-hdpi/actionbar_translucent.9.png
deleted file mode 100644
index f18761f..0000000
--- a/photoviewer/res/drawable-hdpi/actionbar_translucent.9.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.png b/photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.png
deleted file mode 100644
index 69ac31b..0000000
--- a/photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/res/drawable-mdpi/actionbar_translucent.9.png b/photoviewer/res/drawable-mdpi/actionbar_translucent.9.png
deleted file mode 100644
index f78fb8a..0000000
--- a/photoviewer/res/drawable-mdpi/actionbar_translucent.9.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.png b/photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.png
deleted file mode 100644
index f68aacf..0000000
--- a/photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.png b/photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.png
deleted file mode 100644
index 3db90ee..0000000
--- a/photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/res/drawable/default_image.png b/photoviewer/res/drawable/default_image.png
deleted file mode 100644
index f6e6e60..0000000
--- a/photoviewer/res/drawable/default_image.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/res/layout/photo_activity_view.xml b/photoviewer/res/layout/photo_activity_view.xml
deleted file mode 100644
index e273140..0000000
--- a/photoviewer/res/layout/photo_activity_view.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2011 Google Inc.
- Licensed to 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/photo_activity_root_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <com.android.ex.photo.PhotoViewPager
- android:id="@+id/photo_view_pager"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</FrameLayout>
diff --git a/photoviewer/res/layout/photo_fragment_view.xml b/photoviewer/res/layout/photo_fragment_view.xml
deleted file mode 100644
index 3dea9f1..0000000
--- a/photoviewer/res/layout/photo_fragment_view.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2011 Google Inc.
- Licensed to 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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <com.android.ex.photo.views.PhotoView
- android:id="@+id/photo_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <FrameLayout
- android:id="@+id/photo_preview"
- android:layout_width="@dimen/photo_preview_size"
- android:layout_height="@dimen/photo_preview_size"
- android:layout_centerInParent="true" >
-
- <ImageView
- android:id="@+id/photo_preview_image"
- android:layout_width="@dimen/photo_preview_size"
- android:layout_height="@dimen/photo_preview_size"
- android:layout_gravity="center"
- android:scaleType="centerCrop"
- android:src="@drawable/default_image"
- android:visibility="gone" />
-
- <ProgressBar
- android:id="@+id/indeterminate_progress"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="@dimen/photo_preview_size"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:indeterminate="true"
- android:visibility="gone" />
-
- <ProgressBar
- android:id="@+id/determinate_progress"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="@dimen/photo_preview_size"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:indeterminate="false"
- android:visibility="gone" />
- </FrameLayout>
-
- <TextView
- android:id="@+id/empty_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/photo_preview"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="8dip"
- android:textColor="@android:color/white"
- android:visibility="gone" />
-
- <ImageView
- android:id="@+id/retry_button"
- android:layout_width="@dimen/retry_button_size"
- android:layout_height="@dimen/retry_button_size"
- android:layout_below="@id/empty_text"
- android:layout_centerHorizontal="true"
- android:background="?android:attr/selectableItemBackground"
- android:scaleType="center"
- android:src="@drawable/ic_menu_refresh_holo_dark"
- android:visibility="gone" />
-
-</RelativeLayout>
diff --git a/photoviewer/res/values-af/strings.xml b/photoviewer/res/values-af/strings.xml
deleted file mode 100644
index 9c3ca85..0000000
--- a/photoviewer/res/values-af/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> van <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Herprobeer"</string>
-</resources>
diff --git a/photoviewer/res/values-am/strings.xml b/photoviewer/res/values-am/strings.xml
deleted file mode 100644
index e1506bb..0000000
--- a/photoviewer/res/values-am/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> ከ<xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"እንደገና ሞክር"</string>
-</resources>
diff --git a/photoviewer/res/values-ar/strings.xml b/photoviewer/res/values-ar/strings.xml
deleted file mode 100644
index d98e088..0000000
--- a/photoviewer/res/values-ar/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> من <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"إعادة المحاولة"</string>
-</resources>
diff --git a/photoviewer/res/values-be/strings.xml b/photoviewer/res/values-be/strings.xml
deleted file mode 100644
index 93304c7..0000000
--- a/photoviewer/res/values-be/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> з <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Паўтарыць спробу"</string>
-</resources>
diff --git a/photoviewer/res/values-bg/strings.xml b/photoviewer/res/values-bg/strings.xml
deleted file mode 100644
index 58d4a2b..0000000
--- a/photoviewer/res/values-bg/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> от <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Нов опит"</string>
-</resources>
diff --git a/photoviewer/res/values-ca/strings.xml b/photoviewer/res/values-ca/strings.xml
deleted file mode 100644
index 4d46071..0000000
--- a/photoviewer/res/values-ca/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> de <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Torna-ho a provar"</string>
-</resources>
diff --git a/photoviewer/res/values-cs/strings.xml b/photoviewer/res/values-cs/strings.xml
deleted file mode 100644
index 0d51d1b..0000000
--- a/photoviewer/res/values-cs/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> z <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Opakovat"</string>
-</resources>
diff --git a/photoviewer/res/values-da/strings.xml b/photoviewer/res/values-da/strings.xml
deleted file mode 100644
index fc9dd30..0000000
--- a/photoviewer/res/values-da/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> af <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Forsøg igen"</string>
-</resources>
diff --git a/photoviewer/res/values-de/strings.xml b/photoviewer/res/values-de/strings.xml
deleted file mode 100644
index 14bb59c..0000000
--- a/photoviewer/res/values-de/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> von <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Wiederholen"</string>
-</resources>
diff --git a/photoviewer/res/values-el/strings.xml b/photoviewer/res/values-el/strings.xml
deleted file mode 100644
index 3292172..0000000
--- a/photoviewer/res/values-el/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> από <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Επανάληψη"</string>
-</resources>
diff --git a/photoviewer/res/values-en-rGB/strings.xml b/photoviewer/res/values-en-rGB/strings.xml
deleted file mode 100644
index c6e5289..0000000
--- a/photoviewer/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> of <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Retry"</string>
-</resources>
diff --git a/photoviewer/res/values-es-rUS/strings.xml b/photoviewer/res/values-es-rUS/strings.xml
deleted file mode 100644
index ffa0414..0000000
--- a/photoviewer/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> de <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Intentar nuevamente"</string>
-</resources>
diff --git a/photoviewer/res/values-es/strings.xml b/photoviewer/res/values-es/strings.xml
deleted file mode 100644
index 9fa6031..0000000
--- a/photoviewer/res/values-es/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> de <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Volver a intentar"</string>
-</resources>
diff --git a/photoviewer/res/values-et/strings.xml b/photoviewer/res/values-et/strings.xml
deleted file mode 100644
index 888c1f9..0000000
--- a/photoviewer/res/values-et/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g>/<xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Proovi uuesti"</string>
-</resources>
diff --git a/photoviewer/res/values-fa/strings.xml b/photoviewer/res/values-fa/strings.xml
deleted file mode 100644
index 5ebd26b..0000000
--- a/photoviewer/res/values-fa/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> از <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"سعی مجدد"</string>
-</resources>
diff --git a/photoviewer/res/values-fi/strings.xml b/photoviewer/res/values-fi/strings.xml
deleted file mode 100644
index ea9ccc8..0000000
--- a/photoviewer/res/values-fi/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g>/<xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Yritä uudelleen"</string>
-</resources>
diff --git a/photoviewer/res/values-fr/strings.xml b/photoviewer/res/values-fr/strings.xml
deleted file mode 100644
index 6a55c27..0000000
--- a/photoviewer/res/values-fr/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> sur <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Réessayer"</string>
-</resources>
diff --git a/photoviewer/res/values-hi/strings.xml b/photoviewer/res/values-hi/strings.xml
deleted file mode 100644
index 54d9612..0000000
--- a/photoviewer/res/values-hi/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="COUNT">%d</xliff:g> में से <xliff:g id="CURRENT_POS">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"पुनः प्रयास करें"</string>
-</resources>
diff --git a/photoviewer/res/values-hr/strings.xml b/photoviewer/res/values-hr/strings.xml
deleted file mode 100644
index e10f61a..0000000
--- a/photoviewer/res/values-hr/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> od <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Pokušaj ponovo"</string>
-</resources>
diff --git a/photoviewer/res/values-hu/strings.xml b/photoviewer/res/values-hu/strings.xml
deleted file mode 100644
index bb5afbe..0000000
--- a/photoviewer/res/values-hu/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="COUNT">%d</xliff:g>/<xliff:g id="CURRENT_POS">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Újra"</string>
-</resources>
diff --git a/photoviewer/res/values-in/strings.xml b/photoviewer/res/values-in/strings.xml
deleted file mode 100644
index d982638..0000000
--- a/photoviewer/res/values-in/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> dari <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Coba lagi"</string>
-</resources>
diff --git a/photoviewer/res/values-it/strings.xml b/photoviewer/res/values-it/strings.xml
deleted file mode 100644
index 77bf13a..0000000
--- a/photoviewer/res/values-it/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> di <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Riprova"</string>
-</resources>
diff --git a/photoviewer/res/values-iw/strings.xml b/photoviewer/res/values-iw/strings.xml
deleted file mode 100644
index 450b159..0000000
--- a/photoviewer/res/values-iw/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> מתוך <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"נסה שנית"</string>
-</resources>
diff --git a/photoviewer/res/values-ja/strings.xml b/photoviewer/res/values-ja/strings.xml
deleted file mode 100644
index 0362113..0000000
--- a/photoviewer/res/values-ja/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g>/<xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"再試行"</string>
-</resources>
diff --git a/photoviewer/res/values-ko/strings.xml b/photoviewer/res/values-ko/strings.xml
deleted file mode 100644
index 150112d..0000000
--- a/photoviewer/res/values-ko/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g>/<xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"다시 시도"</string>
-</resources>
diff --git a/photoviewer/res/values-lt/strings.xml b/photoviewer/res/values-lt/strings.xml
deleted file mode 100644
index 7c32566..0000000
--- a/photoviewer/res/values-lt/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> iš <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Bandyti dar kartą"</string>
-</resources>
diff --git a/photoviewer/res/values-lv/strings.xml b/photoviewer/res/values-lv/strings.xml
deleted file mode 100644
index 0857782..0000000
--- a/photoviewer/res/values-lv/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g>. no <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Mēģināt vēlreiz"</string>
-</resources>
diff --git a/photoviewer/res/values-ms/strings.xml b/photoviewer/res/values-ms/strings.xml
deleted file mode 100644
index ec0d23a..0000000
--- a/photoviewer/res/values-ms/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> daripada <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Cuba semula"</string>
-</resources>
diff --git a/photoviewer/res/values-nb/strings.xml b/photoviewer/res/values-nb/strings.xml
deleted file mode 100644
index b533fc9..0000000
--- a/photoviewer/res/values-nb/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> av <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Prøv på nytt"</string>
-</resources>
diff --git a/photoviewer/res/values-nl/strings.xml b/photoviewer/res/values-nl/strings.xml
deleted file mode 100644
index e61b149..0000000
--- a/photoviewer/res/values-nl/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> van <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Opnieuw proberen"</string>
-</resources>
diff --git a/photoviewer/res/values-pl/strings.xml b/photoviewer/res/values-pl/strings.xml
deleted file mode 100644
index fe33696..0000000
--- a/photoviewer/res/values-pl/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> z <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Spróbuj ponownie"</string>
-</resources>
diff --git a/photoviewer/res/values-pt-rPT/strings.xml b/photoviewer/res/values-pt-rPT/strings.xml
deleted file mode 100644
index cc62c4a..0000000
--- a/photoviewer/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> de <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Tentar novamente"</string>
-</resources>
diff --git a/photoviewer/res/values-pt/strings.xml b/photoviewer/res/values-pt/strings.xml
deleted file mode 100644
index cc62c4a..0000000
--- a/photoviewer/res/values-pt/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> de <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Tentar novamente"</string>
-</resources>
diff --git a/photoviewer/res/values-ro/strings.xml b/photoviewer/res/values-ro/strings.xml
deleted file mode 100644
index 6c4b724..0000000
--- a/photoviewer/res/values-ro/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> din <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Reîncercaţi"</string>
-</resources>
diff --git a/photoviewer/res/values-ru/strings.xml b/photoviewer/res/values-ru/strings.xml
deleted file mode 100644
index 590adbc..0000000
--- a/photoviewer/res/values-ru/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> из <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Повторить"</string>
-</resources>
diff --git a/photoviewer/res/values-sk/strings.xml b/photoviewer/res/values-sk/strings.xml
deleted file mode 100644
index a9f6616..0000000
--- a/photoviewer/res/values-sk/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> z <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Skúsiť znovu"</string>
-</resources>
diff --git a/photoviewer/res/values-sl/strings.xml b/photoviewer/res/values-sl/strings.xml
deleted file mode 100644
index 816b946..0000000
--- a/photoviewer/res/values-sl/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> od <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Znova"</string>
-</resources>
diff --git a/photoviewer/res/values-sr/strings.xml b/photoviewer/res/values-sr/strings.xml
deleted file mode 100644
index 43fb7b1..0000000
--- a/photoviewer/res/values-sr/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> од <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Покушај поново"</string>
-</resources>
diff --git a/photoviewer/res/values-sv/strings.xml b/photoviewer/res/values-sv/strings.xml
deleted file mode 100644
index 8eef180..0000000
--- a/photoviewer/res/values-sv/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> av <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Försök igen"</string>
-</resources>
diff --git a/photoviewer/res/values-sw/strings.xml b/photoviewer/res/values-sw/strings.xml
deleted file mode 100644
index 3253357..0000000
--- a/photoviewer/res/values-sw/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> ya <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Jaribu tena"</string>
-</resources>
diff --git a/photoviewer/res/values-th/strings.xml b/photoviewer/res/values-th/strings.xml
deleted file mode 100644
index de409e8..0000000
--- a/photoviewer/res/values-th/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> จาก <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"ลองอีกครั้ง"</string>
-</resources>
diff --git a/photoviewer/res/values-tl/strings.xml b/photoviewer/res/values-tl/strings.xml
deleted file mode 100644
index 40b4a77..0000000
--- a/photoviewer/res/values-tl/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> ng <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Subukang muli"</string>
-</resources>
diff --git a/photoviewer/res/values-tr/strings.xml b/photoviewer/res/values-tr/strings.xml
deleted file mode 100644
index 0b2b9e6..0000000
--- a/photoviewer/res/values-tr/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> / <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Yeniden dene"</string>
-</resources>
diff --git a/photoviewer/res/values-uk/strings.xml b/photoviewer/res/values-uk/strings.xml
deleted file mode 100644
index 77b3c08..0000000
--- a/photoviewer/res/values-uk/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> з <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Повторити"</string>
-</resources>
diff --git a/photoviewer/res/values-vi/strings.xml b/photoviewer/res/values-vi/strings.xml
deleted file mode 100644
index 851d793..0000000
--- a/photoviewer/res/values-vi/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> trong số <xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Thử lại"</string>
-</resources>
diff --git a/photoviewer/res/values-zh-rCN/strings.xml b/photoviewer/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 65d8b03..0000000
--- a/photoviewer/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"第 <xliff:g id="CURRENT_POS">%d</xliff:g> 张,共 <xliff:g id="COUNT">%d</xliff:g> 张"</string>
- <string name="retry" msgid="3319517143224679074">"重试"</string>
-</resources>
diff --git a/photoviewer/res/values-zh-rTW/strings.xml b/photoviewer/res/values-zh-rTW/strings.xml
deleted file mode 100644
index fa555d0..0000000
--- a/photoviewer/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"第 <xliff:g id="CURRENT_POS">%d</xliff:g> 張 (共 <xliff:g id="COUNT">%d</xliff:g> 張)"</string>
- <string name="retry" msgid="3319517143224679074">"重試"</string>
-</resources>
diff --git a/photoviewer/res/values-zu/strings.xml b/photoviewer/res/values-zu/strings.xml
deleted file mode 100644
index 31aec64..0000000
--- a/photoviewer/res/values-zu/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="photo_view_count" msgid="3466690572899800275">"<xliff:g id="CURRENT_POS">%d</xliff:g> kwe-<xliff:g id="COUNT">%d</xliff:g>"</string>
- <string name="retry" msgid="3319517143224679074">"Zama futhi"</string>
-</resources>
diff --git a/photoviewer/res/values/colors.xml b/photoviewer/res/values/colors.xml
deleted file mode 100644
index cd2a14b..0000000
--- a/photoviewer/res/values/colors.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2011 Google Inc.
- Licensed to 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.
--->
-<resources>
- <!-- Photo Viewer Colors -->
- <color name="solid_black">#ff000000</color>
- <color name="photo_crop_dim_color">#cc000000</color>
- <color name="photo_crop_highlight_color">#fff</color>
-</resources>
diff --git a/photoviewer/res/values/constants.xml b/photoviewer/res/values/constants.xml
deleted file mode 100644
index ae480ce..0000000
--- a/photoviewer/res/values/constants.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
--->
-
-<resources>
- <integer name="action_bar_delay_time_in_millis">5000</integer>
-</resources>
diff --git a/photoviewer/res/values/dimen.xml b/photoviewer/res/values/dimen.xml
deleted file mode 100644
index 754c99b..0000000
--- a/photoviewer/res/values/dimen.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
--->
-
-<resources>
- <dimen name="photo_crop_width">280dip</dimen>
- <dimen name="photo_crop_stroke_width">1dip</dimen>
- <dimen name="photo_preview_size">200dip</dimen>
- <dimen name="retry_button_size">48dip</dimen>
- <dimen name="photo_page_margin">32dip</dimen>
-</resources>
diff --git a/photoviewer/res/values/strings.xml b/photoviewer/res/values/strings.xml
deleted file mode 100644
index b635122..0000000
--- a/photoviewer/res/values/strings.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Photo view sub-title for current photo position [CHAR LIMIT=10] -->
- <string name="photo_view_count"><xliff:g id="current_pos">%d</xliff:g> of <xliff:g id="count">%d</xliff:g></string>
- <string name="retry">Retry</string>
-</resources> \ No newline at end of file
diff --git a/photoviewer/res/values/themes.xml b/photoviewer/res/values/themes.xml
deleted file mode 100644
index 04bec53..0000000
--- a/photoviewer/res/values/themes.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2012 Google Inc.
- Licensed to 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.
--->
-
-<resources>
- <style name="PhotoViewTheme" parent="android:Theme.Holo">
- <item name="android:windowNoTitle">false</item>
- <item name="android:windowContentOverlay">@null</item>
- <item name="android:windowActionBarOverlay">true</item>
- <item name="android:windowBackground">@color/solid_black</item>
- <item name="android:actionBarStyle">@style/Holo.ActionBar</item>
- </style>
- <style name="Holo.ActionBar" parent="android:Widget.Holo.ActionBar">
- <item name="android:background">@drawable/actionbar_translucent</item>
- </style>
-</resources>
diff --git a/photoviewer/sample/Android.mk b/photoviewer/sample/Android.mk
deleted file mode 100644
index 8346e7c..0000000
--- a/photoviewer/sample/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-#Include res dir from photoviewer
-photo_dir := ..//res
-res_dirs := $(photo_dir) res
-
-##################################################
-# Build APK
-include $(CLEAR_VARS)
-
-src_dirs := src
-LOCAL_PACKAGE_NAME := PhotoViewerSample
-
-LOCAL_STATIC_JAVA_LIBRARIES += android-common-photoviewer
-LOCAL_STATIC_JAVA_LIBRARIES += android-common
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4
-LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
-
-LOCAL_SDK_VERSION := 16
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs)) \
- $(call all-logtags-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs)) $(LOCAL_PATH)/res
-LOCAL_AAPT_FLAGS := --auto-add-overlay
-LOCAL_AAPT_FLAGS += --extra-packages com.android.ex.photo
-
-include $(BUILD_PACKAGE)
-
-
-##################################################
-# Build all sub-directories
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/photoviewer/sample/AndroidManifest.xml b/photoviewer/sample/AndroidManifest.xml
deleted file mode 100644
index 8a75d6a..0000000
--- a/photoviewer/sample/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.photoviewersample"
- android:versionCode="1"
- android:versionName="1.0" >
-
- <uses-sdk
- android:minSdkVersion="14"
- android:targetSdkVersion="16" />
-
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name="com.android.ex.photo.PhotoViewActivity"
- android:label="@string/app_name"
- android:theme="@style/PhotoViewTheme" >
- </activity>
- <provider
- android:name=".SampleProvider"
- android:exported="false"
- android:authorities="com.example.photoviewersample.SampleProvider">
- </provider>
- </application>
-
-</manifest> \ No newline at end of file
diff --git a/photoviewer/sample/assets/blah.png b/photoviewer/sample/assets/blah.png
deleted file mode 100644
index f895669..0000000
--- a/photoviewer/sample/assets/blah.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/assets/galaxy.png b/photoviewer/sample/assets/galaxy.png
deleted file mode 100644
index 3fcfec8..0000000
--- a/photoviewer/sample/assets/galaxy.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/assets/johannson.png b/photoviewer/sample/assets/johannson.png
deleted file mode 100644
index 0b6be7f..0000000
--- a/photoviewer/sample/assets/johannson.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/assets/planets.png b/photoviewer/sample/assets/planets.png
deleted file mode 100644
index 1644c48..0000000
--- a/photoviewer/sample/assets/planets.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/res/drawable-hdpi/ic_action_search.png b/photoviewer/sample/res/drawable-hdpi/ic_action_search.png
deleted file mode 100644
index 67de12d..0000000
--- a/photoviewer/sample/res/drawable-hdpi/ic_action_search.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/res/drawable-hdpi/ic_launcher.png b/photoviewer/sample/res/drawable-hdpi/ic_launcher.png
deleted file mode 100644
index fba1ff0..0000000
--- a/photoviewer/sample/res/drawable-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/res/drawable-mdpi/ic_action_search.png b/photoviewer/sample/res/drawable-mdpi/ic_action_search.png
deleted file mode 100644
index 134d549..0000000
--- a/photoviewer/sample/res/drawable-mdpi/ic_action_search.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/res/drawable-mdpi/ic_launcher.png b/photoviewer/sample/res/drawable-mdpi/ic_launcher.png
deleted file mode 100644
index 72a445d..0000000
--- a/photoviewer/sample/res/drawable-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/res/drawable-xhdpi/ic_action_search.png b/photoviewer/sample/res/drawable-xhdpi/ic_action_search.png
deleted file mode 100644
index d699c6b..0000000
--- a/photoviewer/sample/res/drawable-xhdpi/ic_action_search.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/res/drawable-xhdpi/ic_launcher.png b/photoviewer/sample/res/drawable-xhdpi/ic_launcher.png
deleted file mode 100644
index 002e7b0..0000000
--- a/photoviewer/sample/res/drawable-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/photoviewer/sample/res/layout/activity_main.xml b/photoviewer/sample/res/layout/activity_main.xml
deleted file mode 100644
index ae94392..0000000
--- a/photoviewer/sample/res/layout/activity_main.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <Button
- android:id="@+id/button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:padding="@dimen/padding_medium"
- android:text="@string/launch"
- tools:context=".MainActivity" />
-
-</RelativeLayout>
diff --git a/photoviewer/sample/res/menu/activity_main.xml b/photoviewer/sample/res/menu/activity_main.xml
deleted file mode 100644
index cfc10fd..0000000
--- a/photoviewer/sample/res/menu/activity_main.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/menu_settings"
- android:title="@string/menu_settings"
- android:orderInCategory="100"
- android:showAsAction="never" />
-</menu>
diff --git a/photoviewer/sample/res/values-af/strings.xml b/photoviewer/sample/res/values-af/strings.xml
deleted file mode 100644
index 952a3b5..0000000
--- a/photoviewer/sample/res/values-af/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Instellings"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Begin fotokyker"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-am/strings.xml b/photoviewer/sample/res/values-am/strings.xml
deleted file mode 100644
index 0d4989a..0000000
--- a/photoviewer/sample/res/values-am/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"ቅንብሮች"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"ፎቶ ተመልካችን አስነሳ"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-ar/strings.xml b/photoviewer/sample/res/values-ar/strings.xml
deleted file mode 100644
index 8f71f28..0000000
--- a/photoviewer/sample/res/values-ar/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"الإعدادات"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"تشغيل عارض الصور"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-be/strings.xml b/photoviewer/sample/res/values-be/strings.xml
deleted file mode 100644
index d52e8ad..0000000
--- a/photoviewer/sample/res/values-be/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Налады"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Запусцiць Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-bg/strings.xml b/photoviewer/sample/res/values-bg/strings.xml
deleted file mode 100644
index 37d2ea7..0000000
--- a/photoviewer/sample/res/values-bg/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Настройки"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Стартиране на Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-ca/strings.xml b/photoviewer/sample/res/values-ca/strings.xml
deleted file mode 100644
index 11ca3ff..0000000
--- a/photoviewer/sample/res/values-ca/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"Mostra del lector de fotos"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Configuració"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Activitat principal"</string>
- <string name="launch" msgid="2345080120370773520">"Inicia el lector de fotos"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-cs/strings.xml b/photoviewer/sample/res/values-cs/strings.xml
deleted file mode 100644
index 8f222fc..0000000
--- a/photoviewer/sample/res/values-cs/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"Příklad prohlížeče fotografií"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Nastavení"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Hlavní aktivita"</string>
- <string name="launch" msgid="2345080120370773520">"Spustit prohlížeč fotografií"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-da/strings.xml b/photoviewer/sample/res/values-da/strings.xml
deleted file mode 100644
index 4a8d3c7..0000000
--- a/photoviewer/sample/res/values-da/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Indstillinger"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Start fotofremviser"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-de/strings.xml b/photoviewer/sample/res/values-de/strings.xml
deleted file mode 100644
index 03f1ba6..0000000
--- a/photoviewer/sample/res/values-de/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Einstellungen"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Photo Viewer starten"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-el/strings.xml b/photoviewer/sample/res/values-el/strings.xml
deleted file mode 100644
index 6e5ec4a..0000000
--- a/photoviewer/sample/res/values-el/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Ρυθμίσεις"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Εκκίνηση του Προγράμματος προβολής φωτογραφιών"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-en-rGB/strings.xml b/photoviewer/sample/res/values-en-rGB/strings.xml
deleted file mode 100644
index 66a0898..0000000
--- a/photoviewer/sample/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Settings"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Launch Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-es-rUS/strings.xml b/photoviewer/sample/res/values-es-rUS/strings.xml
deleted file mode 100644
index ab4e5a0..0000000
--- a/photoviewer/sample/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Configuración"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Actividad principal"</string>
- <string name="launch" msgid="2345080120370773520">"Iniciar Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-es/strings.xml b/photoviewer/sample/res/values-es/strings.xml
deleted file mode 100644
index 8af0dbc..0000000
--- a/photoviewer/sample/res/values-es/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"Ejemplo de Photo Viewer"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Ajustes"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Actividad principal"</string>
- <string name="launch" msgid="2345080120370773520">"Iniciar Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-et/strings.xml b/photoviewer/sample/res/values-et/strings.xml
deleted file mode 100644
index 9532a25..0000000
--- a/photoviewer/sample/res/values-et/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Seaded"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Fotovaaturi käivitamine"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-fa/strings.xml b/photoviewer/sample/res/values-fa/strings.xml
deleted file mode 100644
index ea17cdb..0000000
--- a/photoviewer/sample/res/values-fa/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"نمونه نمایشگر تصویر"</string>
- <string name="menu_settings" msgid="1259682084875185697">"تنظیمات"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"راه‌اندازی نمایشگر تصویر"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-fi/strings.xml b/photoviewer/sample/res/values-fi/strings.xml
deleted file mode 100644
index 7bd9359..0000000
--- a/photoviewer/sample/res/values-fi/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Asetukset"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Käynnistä Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-fr/strings.xml b/photoviewer/sample/res/values-fr/strings.xml
deleted file mode 100644
index 6e3cf79..0000000
--- a/photoviewer/sample/res/values-fr/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Paramètres"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Lancer la visionneuse de photos"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-hi/strings.xml b/photoviewer/sample/res/values-hi/strings.xml
deleted file mode 100644
index 33f30b0..0000000
--- a/photoviewer/sample/res/values-hi/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"सेटिंग"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"फ़ोटो व्यूअर लॉन्च करें"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-hr/strings.xml b/photoviewer/sample/res/values-hr/strings.xml
deleted file mode 100644
index c5f11d0..0000000
--- a/photoviewer/sample/res/values-hr/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Postavke"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Pokreni Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-hu/strings.xml b/photoviewer/sample/res/values-hu/strings.xml
deleted file mode 100644
index 6a38dba..0000000
--- a/photoviewer/sample/res/values-hu/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Beállítások"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"A Photo Viewer elindítása"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-in/strings.xml b/photoviewer/sample/res/values-in/strings.xml
deleted file mode 100644
index ac1e887..0000000
--- a/photoviewer/sample/res/values-in/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Setelan"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Luncurkan Penampil Foto"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-it/strings.xml b/photoviewer/sample/res/values-it/strings.xml
deleted file mode 100644
index 7c37c68..0000000
--- a/photoviewer/sample/res/values-it/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Impostazioni"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Avvia Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-iw/strings.xml b/photoviewer/sample/res/values-iw/strings.xml
deleted file mode 100644
index 5087894..0000000
--- a/photoviewer/sample/res/values-iw/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"הגדרות"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"הפעל את מציג התמונות"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-ja/strings.xml b/photoviewer/sample/res/values-ja/strings.xml
deleted file mode 100644
index d5bdf48..0000000
--- a/photoviewer/sample/res/values-ja/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"設定"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"フォトビューアを起動"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-ko/strings.xml b/photoviewer/sample/res/values-ko/strings.xml
deleted file mode 100644
index 0366b9e..0000000
--- a/photoviewer/sample/res/values-ko/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"사진 뷰어 샘플"</string>
- <string name="menu_settings" msgid="1259682084875185697">"설정"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"주요 활동"</string>
- <string name="launch" msgid="2345080120370773520">"사진 뷰어 실행"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-lt/strings.xml b/photoviewer/sample/res/values-lt/strings.xml
deleted file mode 100644
index fe66735..0000000
--- a/photoviewer/sample/res/values-lt/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"Nuotraukų peržiūros priemonės pavyzdys"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Nustatymai"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Pagrindinė veikla"</string>
- <string name="launch" msgid="2345080120370773520">"Paleisti nuotraukų peržiūros priemonę"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-lv/strings.xml b/photoviewer/sample/res/values-lv/strings.xml
deleted file mode 100644
index 43ffeec..0000000
--- a/photoviewer/sample/res/values-lv/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"Fotoattēlu skatītāja paraugs"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Iestatījumi"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Galvenās darbības"</string>
- <string name="launch" msgid="2345080120370773520">"Palaist fotoattēlu skatītāju"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-ms/strings.xml b/photoviewer/sample/res/values-ms/strings.xml
deleted file mode 100644
index 8ad0bca..0000000
--- a/photoviewer/sample/res/values-ms/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Tetapan"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Aktiviti Utama"</string>
- <string name="launch" msgid="2345080120370773520">"Lancarkan Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-nb/strings.xml b/photoviewer/sample/res/values-nb/strings.xml
deleted file mode 100644
index 85e04e6..0000000
--- a/photoviewer/sample/res/values-nb/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Innstillinger"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Start Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-nl/strings.xml b/photoviewer/sample/res/values-nl/strings.xml
deleted file mode 100644
index 6a4b531..0000000
--- a/photoviewer/sample/res/values-nl/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Instellingen"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Fotoviewer starten"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-pl/strings.xml b/photoviewer/sample/res/values-pl/strings.xml
deleted file mode 100644
index 282bde1..0000000
--- a/photoviewer/sample/res/values-pl/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Ustawienia"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Uruchom przeglądarkę zdjęć"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-pt-rPT/strings.xml b/photoviewer/sample/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 46f8f28..0000000
--- a/photoviewer/sample/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"ExemploVisualizadorFotos"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Definições"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"AtividadePrincipal"</string>
- <string name="launch" msgid="2345080120370773520">"Iniciar Visualizador de Fotos"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-pt/strings.xml b/photoviewer/sample/res/values-pt/strings.xml
deleted file mode 100644
index 16e146a..0000000
--- a/photoviewer/sample/res/values-pt/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"AmostraPhotoViewer"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Configurações"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"AtividadePrincipal"</string>
- <string name="launch" msgid="2345080120370773520">"Iniciar o Visualizador de fotos"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-ro/strings.xml b/photoviewer/sample/res/values-ro/strings.xml
deleted file mode 100644
index 00f370e..0000000
--- a/photoviewer/sample/res/values-ro/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Setări"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Lansaţi Photo Viewer"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-ru/strings.xml b/photoviewer/sample/res/values-ru/strings.xml
deleted file mode 100644
index 2f68e2d..0000000
--- a/photoviewer/sample/res/values-ru/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Настройки"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Основные действия"</string>
- <string name="launch" msgid="2345080120370773520">"Смотреть фото"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-sk/strings.xml b/photoviewer/sample/res/values-sk/strings.xml
deleted file mode 100644
index a7e5d7b..0000000
--- a/photoviewer/sample/res/values-sk/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"Príklad prehliadača fotografií"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Nastavenia"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"Hlavná aktivita"</string>
- <string name="launch" msgid="2345080120370773520">"Spustiť prehliadač fotografií"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-sl/strings.xml b/photoviewer/sample/res/values-sl/strings.xml
deleted file mode 100644
index b365610..0000000
--- a/photoviewer/sample/res/values-sl/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Nastavitve"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Zaženi pregledovalnik fotografij"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-sr/strings.xml b/photoviewer/sample/res/values-sr/strings.xml
deleted file mode 100644
index ed2433f..0000000
--- a/photoviewer/sample/res/values-sr/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Подешавања"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Покрени фото прегледач"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-sv/strings.xml b/photoviewer/sample/res/values-sv/strings.xml
deleted file mode 100644
index ffd5e95..0000000
--- a/photoviewer/sample/res/values-sv/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Inställningar"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Starta fotovisaren"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-sw/strings.xml b/photoviewer/sample/res/values-sw/strings.xml
deleted file mode 100644
index 6e6b913..0000000
--- a/photoviewer/sample/res/values-sw/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"SampuliKionyeshaPicha"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Mipangilio"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"ShughuliKuu"</string>
- <string name="launch" msgid="2345080120370773520">"Zindua Kionyesha Picha"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-th/strings.xml b/photoviewer/sample/res/values-th/strings.xml
deleted file mode 100644
index 1643fe2..0000000
--- a/photoviewer/sample/res/values-th/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"ตัวอย่างโปรแกรมดูรูปภาพ"</string>
- <string name="menu_settings" msgid="1259682084875185697">"การตั้งค่า"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"กิจกรรมหลัก"</string>
- <string name="launch" msgid="2345080120370773520">"เปิดโปรแกรมดูรูปภาพ"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-tl/strings.xml b/photoviewer/sample/res/values-tl/strings.xml
deleted file mode 100644
index c815b11..0000000
--- a/photoviewer/sample/res/values-tl/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Mga Setting"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Ilunsad ang Viewer ng Larawan"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-tr/strings.xml b/photoviewer/sample/res/values-tr/strings.xml
deleted file mode 100644
index 8ef780f..0000000
--- a/photoviewer/sample/res/values-tr/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Ayarlar"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Photo Viewer\'ı Başlat"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-uk/strings.xml b/photoviewer/sample/res/values-uk/strings.xml
deleted file mode 100644
index dc813ab..0000000
--- a/photoviewer/sample/res/values-uk/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Налаштування"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Запустити інструмент перегляду фотографій"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-vi/strings.xml b/photoviewer/sample/res/values-vi/strings.xml
deleted file mode 100644
index 910a52c..0000000
--- a/photoviewer/sample/res/values-vi/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Cài đặt"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Khởi chạy trình xem ảnh"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-zh-rCN/strings.xml b/photoviewer/sample/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 69795a6..0000000
--- a/photoviewer/sample/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"设置"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"启动照片浏览器"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-zh-rTW/strings.xml b/photoviewer/sample/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 73dd1fa..0000000
--- a/photoviewer/sample/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"設定"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"啟動相片檢視器"</string>
-</resources>
diff --git a/photoviewer/sample/res/values-zu/strings.xml b/photoviewer/sample/res/values-zu/strings.xml
deleted file mode 100644
index e42c901..0000000
--- a/photoviewer/sample/res/values-zu/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="559800164925277094">"PhotoViewerSample"</string>
- <string name="menu_settings" msgid="1259682084875185697">"Izilungiselelo"</string>
- <string name="title_activity_main" msgid="7695239211427024237">"MainActivity"</string>
- <string name="launch" msgid="2345080120370773520">"Vula isibonisi sesithombe"</string>
-</resources>
diff --git a/photoviewer/sample/res/values/dimens.xml b/photoviewer/sample/res/values/dimens.xml
deleted file mode 100644
index ec96646..0000000
--- a/photoviewer/sample/res/values/dimens.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<resources>
-
- <dimen name="padding_small">8dp</dimen>
- <dimen name="padding_medium">8dp</dimen>
- <dimen name="padding_large">16dp</dimen>
-
-</resources> \ No newline at end of file
diff --git a/photoviewer/sample/res/values/strings.xml b/photoviewer/sample/res/values/strings.xml
deleted file mode 100644
index be31909..0000000
--- a/photoviewer/sample/res/values/strings.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<resources>
-
- <string name="app_name">PhotoViewerSample</string>
- <string name="menu_settings">Settings</string>
- <string name="title_activity_main">MainActivity</string>
- <string name="launch">Launch Photo Viewer</string>
-
-</resources> \ No newline at end of file
diff --git a/photoviewer/sample/res/values/styles.xml b/photoviewer/sample/res/values/styles.xml
deleted file mode 100644
index 1c089a7..0000000
--- a/photoviewer/sample/res/values/styles.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<resources>
-
- <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
-
-</resources> \ No newline at end of file
diff --git a/photoviewer/sample/src/com/example/photoviewersample/MainActivity.java b/photoviewer/sample/src/com/example/photoviewersample/MainActivity.java
deleted file mode 100644
index efc2064..0000000
--- a/photoviewer/sample/src/com/example/photoviewersample/MainActivity.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.example.photoviewersample;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import com.android.ex.photo.Intents;
-import com.android.ex.photo.Intents.PhotoViewIntentBuilder;
-
-public class MainActivity extends Activity implements OnClickListener {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- View b = findViewById(R.id.button);
- b.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- final PhotoViewIntentBuilder builder =
- Intents.newPhotoViewActivityIntentBuilder(this);
- builder
- .setPhotosUri("content://com.example.photoviewersample.SampleProvider/photos");
-
- startActivity(builder.build());
- }
-}
diff --git a/photoviewer/sample/src/com/example/photoviewersample/SampleProvider.java b/photoviewer/sample/src/com/example/photoviewersample/SampleProvider.java
deleted file mode 100644
index 86ae82b..0000000
--- a/photoviewer/sample/src/com/example/photoviewersample/SampleProvider.java
+++ /dev/null
@@ -1,179 +0,0 @@
-package com.example.photoviewersample;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.content.UriMatcher;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.net.Uri;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.List;
-
-public class SampleProvider extends ContentProvider {
- private static final int PHOTOS = 1;
- private static final int PHOTO_INDIVIDUAL_1 = 2;
- private static final int PHOTO_INDIVIDUAL_2 = 3;
- private static final int PHOTO_INDIVIDUAL_3 = 4;
- private static final int PHOTO_INDIVIDUAL_4 = 5;
-
- private static final String PROVIDER_URI = "com.example.photoviewersample.SampleProvider";
-
- // Creates a UriMatcher object.
- private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
-
- static
- {
- sUriMatcher.addURI(PROVIDER_URI, "photos", PHOTOS);
- sUriMatcher.addURI(PROVIDER_URI, "photos/1", PHOTO_INDIVIDUAL_1);
- sUriMatcher.addURI(PROVIDER_URI, "photos/2", PHOTO_INDIVIDUAL_2);
- sUriMatcher.addURI(PROVIDER_URI, "photos/3", PHOTO_INDIVIDUAL_3);
- sUriMatcher.addURI(PROVIDER_URI, "photos/4", PHOTO_INDIVIDUAL_4);
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public String getType(Uri uri) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public boolean onCreate() {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- MatrixCursor matrix = new MatrixCursor(projection);
-
- /*
- * Choose the table to query and a sort order based on the code returned for the incoming
- * URI. Here, too, only the statements for table 3 are shown.
- */
- switch (sUriMatcher.match(uri)) {
- // If the incoming URI was for all of the photos table
- case PHOTOS:
- addRow(matrix, PHOTO_INDIVIDUAL_1);
- addRow(matrix, PHOTO_INDIVIDUAL_2);
- addRow(matrix, PHOTO_INDIVIDUAL_3);
- addRow(matrix, PHOTO_INDIVIDUAL_4);
- break;
-
- // If the incoming URI was for a single row
- case PHOTO_INDIVIDUAL_1:
- addRow(matrix, PHOTO_INDIVIDUAL_1);
- break;
- case PHOTO_INDIVIDUAL_2:
- addRow(matrix, PHOTO_INDIVIDUAL_2);
- break;
- case PHOTO_INDIVIDUAL_3:
- addRow(matrix, PHOTO_INDIVIDUAL_3);
- break;
- case PHOTO_INDIVIDUAL_4:
- addRow(matrix, PHOTO_INDIVIDUAL_4);
- break;
-
- default:
- // If the URI is not recognized, you should do some error handling here.
- }
- // call the code to actually do the query
-
- return matrix;
- }
-
- /**
- * Adds a single row to the Cursor. A real implementation should
- * check the projection to properly match the columns.
- */
- private void addRow(MatrixCursor matrix, int match_id) {
- switch (match_id) {
- case PHOTO_INDIVIDUAL_1:
- matrix.newRow()
- .add("content://" + PROVIDER_URI + "/photos/1") // uri
- .add("blah.png") // displayName
- .add("content://" + PROVIDER_URI + "/photos/1/contentUri") // contentUri
- .add("content://" + PROVIDER_URI + "/photos/1/thumbnailUri") // thumbnailUri
- .add("image/png"); // contentType
- break;
- case PHOTO_INDIVIDUAL_2:
- matrix.newRow()
- .add("content://" + PROVIDER_URI + "/photos/2") // uri
- .add("johannson.png") // displayName
- .add("content://" + PROVIDER_URI + "/photos/2/contentUri") // contentUri
- .add("content://" + PROVIDER_URI + "/photos/2/thumbnailUri") // thumbnailUri
- .add("image/png"); // contentType
- break;
- case PHOTO_INDIVIDUAL_3:
- matrix.newRow()
- .add("content://" + PROVIDER_URI + "/photos/3") // uri
- .add("planets.png") // displayName
- .add("content://" + PROVIDER_URI + "/photos/3/contentUri") // contentUri
- .add("content://" + PROVIDER_URI + "/photos/3/thumbnailUri") // thumbnailUri
- .add("image/png"); // contentType
- break;
- case PHOTO_INDIVIDUAL_4:
- matrix.newRow()
- .add("content://" + PROVIDER_URI + "/photos/4") // uri
- .add("galaxy.png") // displayName
- .add("content://" + PROVIDER_URI + "/photos/4/contentUri") // contentUri
- .add("content://" + PROVIDER_URI + "/photos/4/thumbnailUri") // thumbnailUri
- .add("image/png"); // contentType
- break;
-
- default:
- // If the URI is not recognized, you should do some error handling here.
- }
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
- public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
- List<String> pathSegments = uri.getPathSegments();
- final int id = Integer.parseInt(pathSegments.get(1));
- String fileName;
- switch (id) {
- case 1:
- fileName = "blah.png";
- break;
- case 2:
- fileName = "johannson.png";
- break;
- case 3:
- fileName = "planets.png";
- break;
- case 4:
- fileName = "galaxy.png";
- break;
- default:
- fileName = null;
- break;
- }
- try {
- return getContext().getAssets().openFd(fileName);
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/Intents.java b/photoviewer/src/com/android/ex/photo/Intents.java
deleted file mode 100644
index 0e64730..0000000
--- a/photoviewer/src/com/android/ex/photo/Intents.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo;
-
-import android.content.ContentProvider;
-import android.content.Context;
-import android.content.Intent;
-
-import com.android.ex.photo.fragments.PhotoViewFragment;
-
-/**
- * Build intents to start app activities
- */
-public class Intents {
- // Intent extras
- public static final String EXTRA_PHOTO_INDEX = "photo_index";
- public static final String EXTRA_PHOTO_ID = "photo_id";
- public static final String EXTRA_PHOTOS_URI = "photos_uri";
- public static final String EXTRA_RESOLVED_PHOTO_URI = "resolved_photo_uri";
- public static final String EXTRA_PROJECTION = "projection";
- public static final String EXTRA_THUMBNAIL_URI = "thumbnail_uri";
-
- /**
- * Gets a photo view intent builder to display the photos from phone activity.
- *
- * @param context The context
- * @return The intent builder
- */
- public static PhotoViewIntentBuilder newPhotoViewActivityIntentBuilder(Context context) {
- return new PhotoViewIntentBuilder(context, PhotoViewActivity.class);
- }
-
- /**
- * Gets a photo view intent builder to display the photo view fragment
- *
- * @param context The context
- * @return The intent builder
- */
- public static PhotoViewIntentBuilder newPhotoViewFragmentIntentBuilder(Context context) {
- return new PhotoViewIntentBuilder(context, PhotoViewFragment.class);
- }
-
- /** Gets a new photo view intent builder */
- public static PhotoViewIntentBuilder newPhotoViewIntentBuilder(
- Context context, Class<? extends PhotoViewActivity> cls) {
- return new PhotoViewIntentBuilder(context, cls);
- }
-
- /** Builder to create a photo view intent */
- public static class PhotoViewIntentBuilder {
- private final Intent mIntent;
-
- /** The index of the photo to show */
- private Integer mPhotoIndex;
- /** The URI of the group of photos to display */
- private String mPhotosUri;
- /** The URL of the photo to display */
- private String mResolvedPhotoUri;
- /** The projection for the query to use; optional */
- private String[] mProjection;
- /** The URI of a thumbnail of the photo to display */
- private String mThumbnailUri;
-
- private PhotoViewIntentBuilder(Context context, Class<?> cls) {
- mIntent = new Intent(context, cls);
- }
-
- /** Sets the photo index */
- public PhotoViewIntentBuilder setPhotoIndex(Integer photoIndex) {
- mPhotoIndex = photoIndex;
- return this;
- }
-
- /** Sets the photos URI */
- public PhotoViewIntentBuilder setPhotosUri(String photosUri) {
- mPhotosUri = photosUri;
- return this;
- }
-
- /** Sets the query projection */
- public PhotoViewIntentBuilder setProjection(String[] projection) {
- mProjection = projection;
- return this;
- }
-
- /** Sets the resolved photo URI. This method is for the case
- * where the URI given to {@link PhotoViewActivity} points directly
- * to a single image and does not need to be resolved via a query
- * to the {@link ContentProvider}. If this value is set, it supersedes
- * {@link #setPhotosUri(String)}. */
- public PhotoViewIntentBuilder setResolvedPhotoUri(String resolvedPhotoUri) {
- mResolvedPhotoUri = resolvedPhotoUri;
- return this;
- }
-
- /**
- * Sets the URI for a thumbnail preview of the photo.
- */
- public PhotoViewIntentBuilder setThumbnailUri(String thumbnailUri) {
- mThumbnailUri = thumbnailUri;
- return this;
- }
-
- /** Build the intent */
- public Intent build() {
- mIntent.setAction(Intent.ACTION_VIEW);
-
- mIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-
- if (mPhotoIndex != null) {
- mIntent.putExtra(EXTRA_PHOTO_INDEX, (int) mPhotoIndex);
- }
-
- if (mPhotosUri != null) {
- mIntent.putExtra(EXTRA_PHOTOS_URI, mPhotosUri);
- }
-
- if (mResolvedPhotoUri != null) {
- mIntent.putExtra(EXTRA_RESOLVED_PHOTO_URI, mResolvedPhotoUri);
- }
-
- if (mProjection != null) {
- mIntent.putExtra(EXTRA_PROJECTION, mProjection);
- }
-
- if (mThumbnailUri != null) {
- mIntent.putExtra(EXTRA_THUMBNAIL_URI, mThumbnailUri);
- }
-
- return mIntent;
- }
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java b/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java
deleted file mode 100644
index 6f126b4..0000000
--- a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo;
-
-import android.app.ActionBar;
-import android.app.ActionBar.OnMenuVisibilityListener;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.Fragment;
-import android.app.LoaderManager.LoaderCallbacks;
-import android.content.Intent;
-import android.content.Loader;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v4.view.ViewPager.OnPageChangeListener;
-import android.view.View;
-
-import com.android.ex.photo.PhotoViewPager.InterceptType;
-import com.android.ex.photo.PhotoViewPager.OnInterceptTouchListener;
-import com.android.ex.photo.adapters.PhotoPagerAdapter;
-import com.android.ex.photo.fragments.PhotoViewFragment;
-import com.android.ex.photo.loaders.PhotoPagerLoader;
-import com.android.ex.photo.provider.PhotoContract;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Activity to view the contents of an album.
- */
-public class PhotoViewActivity extends Activity implements
- LoaderCallbacks<Cursor>, OnPageChangeListener, OnInterceptTouchListener,
- OnMenuVisibilityListener {
-
- /**
- * Listener to be invoked for screen events.
- */
- public static interface OnScreenListener {
-
- /**
- * The full screen state has changed.
- */
- public void onFullScreenChanged(boolean fullScreen);
-
- /**
- * A new view has been activated and the previous view de-activated.
- */
- public void onViewActivated();
-
- /**
- * Called when a right-to-left touch move intercept is about to occur.
- *
- * @param origX the raw x coordinate of the initial touch
- * @param origY the raw y coordinate of the initial touch
- * @return {@code true} if the touch should be intercepted.
- */
- public boolean onInterceptMoveLeft(float origX, float origY);
-
- /**
- * Called when a left-to-right touch move intercept is about to occur.
- *
- * @param origX the raw x coordinate of the initial touch
- * @param origY the raw y coordinate of the initial touch
- * @return {@code true} if the touch should be intercepted.
- */
- public boolean onInterceptMoveRight(float origX, float origY);
- }
-
- public static interface CursorChangedListener {
- /**
- * Called when the cursor that contains the photo list data
- * is updated. Note that there is no guarantee that the cursor
- * will be at the proper position.
- * @param cursor the cursor containing the photo list data
- */
- public void onCursorChanged(Cursor cursor);
- }
-
- private final static String STATE_ITEM_KEY =
- "com.google.android.apps.plus.PhotoViewFragment.ITEM";
- private final static String STATE_FULLSCREEN_KEY =
- "com.google.android.apps.plus.PhotoViewFragment.FULLSCREEN";
-
- private static final int LOADER_PHOTO_LIST = 1;
-
- /** Count used when the real photo count is unknown [but, may be determined] */
- public static final int ALBUM_COUNT_UNKNOWN = -1;
-
- /** Argument key for the dialog message */
- public static final String KEY_MESSAGE = "dialog_message";
-
- public static int sMemoryClass;
-
- /** The URI of the photos we're viewing; may be {@code null} */
- private String mPhotosUri;
- /** The index of the currently viewed photo */
- private int mPhotoIndex;
- /** The query projection to use; may be {@code null} */
- private String[] mProjection;
- /** The total number of photos; only valid if {@link #mIsEmpty} is {@code false}. */
- private int mAlbumCount = ALBUM_COUNT_UNKNOWN;
- /** {@code true} if the view is empty. Otherwise, {@code false}. */
- private boolean mIsEmpty;
- /** The main pager; provides left/right swipe between photos */
- private PhotoViewPager mViewPager;
- /** Adapter to create pager views */
- private PhotoPagerAdapter mAdapter;
- /** Whether or not we're in "full screen" mode */
- private boolean mFullScreen;
- /** The set of listeners wanting full screen state */
- private Set<OnScreenListener> mScreenListeners = new HashSet<OnScreenListener>();
- /** The set of listeners wanting full screen state */
- private Set<CursorChangedListener> mCursorListeners = new HashSet<CursorChangedListener>();
- /** When {@code true}, restart the loader when the activity becomes active */
- private boolean mRestartLoader;
- /** Whether or not this activity is paused */
- private boolean mIsPaused = true;
- private final Handler mHandler = new Handler();
- // TODO Find a better way to do this. We basically want the activity to display the
- // "loading..." progress until the fragment takes over and shows it's own "loading..."
- // progress [located in photo_header_view.xml]. We could potentially have all status displayed
- // by the activity, but, that gets tricky when it comes to screen rotation. For now, we
- // track the loading by this variable which is fragile and may cause phantom "loading..."
- // text.
- private long mActionBarHideDelayTime;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- final ActivityManager mgr = (ActivityManager) getApplicationContext().
- getSystemService(Activity.ACTIVITY_SERVICE);
- sMemoryClass = mgr.getMemoryClass();
-
- Intent mIntent = getIntent();
-
- int currentItem = -1;
- if (savedInstanceState != null) {
- currentItem = savedInstanceState.getInt(STATE_ITEM_KEY, -1);
- mFullScreen = savedInstanceState.getBoolean(STATE_FULLSCREEN_KEY, false);
- }
-
- // uri of the photos to view; optional
- if (mIntent.hasExtra(Intents.EXTRA_PHOTOS_URI)) {
- mPhotosUri = mIntent.getStringExtra(Intents.EXTRA_PHOTOS_URI);
- }
-
- // projection for the query; optional
- // I.f not set, the default projection is used.
- // This projection must include the columns from the default projection.
- if (mIntent.hasExtra(Intents.EXTRA_PROJECTION)) {
- mProjection = mIntent.getStringArrayExtra(Intents.EXTRA_PROJECTION);
- } else {
- mProjection = null;
- }
-
- // Set the current item from the intent if wasn't in the saved instance
- if (mIntent.hasExtra(Intents.EXTRA_PHOTO_INDEX) && currentItem < 0) {
- currentItem = mIntent.getIntExtra(Intents.EXTRA_PHOTO_INDEX, -1);
- }
- mPhotoIndex = currentItem;
-
- setContentView(R.layout.photo_activity_view);
-
- // Create the adapter and add the view pager
- mAdapter = new PhotoPagerAdapter(this, getFragmentManager(), null);
-
- final Resources resources = getResources();
- mViewPager = (PhotoViewPager) findViewById(R.id.photo_view_pager);
- mViewPager.setAdapter(mAdapter);
- mViewPager.setOnPageChangeListener(this);
- mViewPager.setOnInterceptTouchListener(this);
- mViewPager.setPageMargin(resources.getDimensionPixelSize(R.dimen.photo_page_margin));
-
- // Kick off the loader
- getLoaderManager().initLoader(LOADER_PHOTO_LIST, null, this);
-
- final ActionBar actionBar = getActionBar();
- actionBar.setDisplayHomeAsUpEnabled(true);
- mActionBarHideDelayTime = resources.getInteger(R.integer.action_bar_delay_time_in_millis);
- actionBar.addOnMenuVisibilityListener(this);
- actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- setFullScreen(mFullScreen, false);
-
- mIsPaused = false;
- if (mRestartLoader) {
- mRestartLoader = false;
- getLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this);
- }
- }
-
- @Override
- protected void onPause() {
- mIsPaused = true;
-
- super.onPause();
- }
-
- @Override
- public void onBackPressed() {
- // If in full screen mode, toggle mode & eat the 'back'
- if (mFullScreen) {
- toggleFullScreen();
- } else {
- super.onBackPressed();
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
-
- outState.putInt(STATE_ITEM_KEY, mViewPager.getCurrentItem());
- outState.putBoolean(STATE_FULLSCREEN_KEY, mFullScreen);
- }
-
- public void addScreenListener(OnScreenListener listener) {
- mScreenListeners.add(listener);
- }
-
- public void removeScreenListener(OnScreenListener listener) {
- mScreenListeners.remove(listener);
- }
-
- public synchronized void addCursorListener(CursorChangedListener listener) {
- mCursorListeners.add(listener);
- }
-
- public synchronized void removeCursorListener(CursorChangedListener listener) {
- mCursorListeners.remove(listener);
- }
-
- public boolean isFragmentFullScreen(Fragment fragment) {
- if (mViewPager == null || mAdapter == null || mAdapter.getCount() == 0) {
- return mFullScreen;
- }
- return mFullScreen || (mViewPager.getCurrentItem() != mAdapter.getItemPosition(fragment));
- }
-
- public void toggleFullScreen() {
- setFullScreen(!mFullScreen, true);
- }
-
- public void onPhotoRemoved(long photoId) {
- final Cursor data = mAdapter.getCursor();
- if (data == null) {
- // Huh?! How would this happen?
- return;
- }
-
- final int dataCount = data.getCount();
- if (dataCount <= 1) {
- finish();
- return;
- }
-
- getLoaderManager().restartLoader(LOADER_PHOTO_LIST, null, this);
- }
-
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- if (id == LOADER_PHOTO_LIST) {
- return new PhotoPagerLoader(this, Uri.parse(mPhotosUri), mProjection);
- }
- return null;
- }
-
- @Override
- public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
- final int id = loader.getId();
- if (id == LOADER_PHOTO_LIST) {
- if (data == null || data.getCount() == 0) {
- mIsEmpty = true;
- } else {
- mAlbumCount = data.getCount();
-
- // We're paused; don't do anything now, we'll get re-invoked
- // when the activity becomes active again
- // TODO(pwestbro): This shouldn't be necessary, as the loader manager should
- // restart the loader
- if (mIsPaused) {
- mRestartLoader = true;
- return;
- }
- mIsEmpty = false;
-
- // set the selected photo
- int itemIndex = mPhotoIndex;
-
- // Use an index of 0 if the index wasn't specified or couldn't be found
- if (itemIndex < 0) {
- itemIndex = 0;
- }
-
- mAdapter.swapCursor(data);
- notifyCursorListeners(data);
-
- mViewPager.setCurrentItem(itemIndex, false);
- setViewActivated();
- }
- // Update the any action items
- updateActionItems();
- }
- }
-
- protected void updateActionItems() {
- // Do nothing, but allow extending classes to do work
- }
-
- private synchronized void notifyCursorListeners(Cursor data) {
- // tell all of the objects listening for cursor changes
- // that the cursor has changed
- for (CursorChangedListener listener : mCursorListeners) {
- listener.onCursorChanged(data);
- }
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
- // If the loader is reset, remove the reference in the adapter to this cursor
- // TODO(pwestbro): reenable this when b/7075236 is fixed
- // mAdapter.swapCursor(null);
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- }
-
- @Override
- public void onPageSelected(int position) {
- mPhotoIndex = position;
- setViewActivated();
- }
-
- @Override
- public void onPageScrollStateChanged(int state) {
- }
-
- public boolean isFragmentActive(Fragment fragment) {
- if (mViewPager == null || mAdapter == null) {
- return false;
- }
- return mViewPager.getCurrentItem() == mAdapter.getItemPosition(fragment);
- }
-
- public void onFragmentVisible(PhotoViewFragment fragment) {
- updateActionBar(fragment);
- }
-
- @Override
- public InterceptType onTouchIntercept(float origX, float origY) {
- boolean interceptLeft = false;
- boolean interceptRight = false;
-
- for (OnScreenListener listener : mScreenListeners) {
- if (!interceptLeft) {
- interceptLeft = listener.onInterceptMoveLeft(origX, origY);
- }
- if (!interceptRight) {
- interceptRight = listener.onInterceptMoveRight(origX, origY);
- }
- listener.onViewActivated();
- }
-
- if (interceptLeft) {
- if (interceptRight) {
- return InterceptType.BOTH;
- }
- return InterceptType.LEFT;
- } else if (interceptRight) {
- return InterceptType.RIGHT;
- }
- return InterceptType.NONE;
- }
-
- /**
- * Updates the title bar according to the value of {@link #mFullScreen}.
- */
- private void setFullScreen(boolean fullScreen, boolean setDelayedRunnable) {
- final boolean fullScreenChanged = (fullScreen != mFullScreen);
- mFullScreen = fullScreen;
-
- if (mFullScreen) {
- setLightsOutMode(true);
- cancelActionBarHideRunnable();
- } else {
- setLightsOutMode(false);
- if (setDelayedRunnable) {
- postActionBarHideRunnableWithDelay();
- }
- }
-
- if (fullScreenChanged) {
- for (OnScreenListener listener : mScreenListeners) {
- listener.onFullScreenChanged(mFullScreen);
- }
- }
- }
-
- private void postActionBarHideRunnableWithDelay() {
- mHandler.postDelayed(mActionBarHideRunnable,
- mActionBarHideDelayTime);
- }
-
- private void cancelActionBarHideRunnable() {
- mHandler.removeCallbacks(mActionBarHideRunnable);
- }
-
- private void setLightsOutMode(boolean enabled) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- int flags = enabled
- ? View.SYSTEM_UI_FLAG_LOW_PROFILE
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- : View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
-
- // using mViewPager since we have it and we need a view
- mViewPager.setSystemUiVisibility(flags);
- } else {
- final ActionBar actionBar = getActionBar();
- if (enabled) {
- actionBar.hide();
- } else {
- actionBar.show();
- }
- int flags = enabled
- ? View.SYSTEM_UI_FLAG_LOW_PROFILE
- : View.SYSTEM_UI_FLAG_VISIBLE;
- mViewPager.setSystemUiVisibility(flags);
- }
- }
-
- private Runnable mActionBarHideRunnable = new Runnable() {
- @Override
- public void run() {
- PhotoViewActivity.this.setLightsOutMode(true);
- }
- };
-
- public void setViewActivated() {
- for (OnScreenListener listener : mScreenListeners) {
- listener.onViewActivated();
- }
- }
-
- /**
- * Adjusts the activity title and subtitle to reflect the photo name and count.
- */
- protected void updateActionBar(PhotoViewFragment fragment) {
- final int position = mViewPager.getCurrentItem() + 1;
- final String title;
- final String subtitle;
- final boolean hasAlbumCount = mAlbumCount >= 0;
-
- final Cursor cursor = getCursorAtProperPosition();
-
- if (cursor != null) {
- final int photoNameIndex = cursor.getColumnIndex(PhotoContract.PhotoViewColumns.NAME);
- title = cursor.getString(photoNameIndex);
- } else {
- title = null;
- }
-
- if (mIsEmpty || !hasAlbumCount || position <= 0) {
- subtitle = null;
- } else {
- subtitle = getResources().getString(R.string.photo_view_count, position, mAlbumCount);
- }
-
- final ActionBar actionBar = getActionBar();
- actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
- actionBar.setTitle(title);
- actionBar.setSubtitle(subtitle);
- }
-
- /**
- * Utility method that will return the cursor that contains the data
- * at the current position so that it refers to the current image on screen.
- * @return the cursor at the current position or
- * null if no cursor exists or if the {@link PhotoViewPager} is null.
- */
- public Cursor getCursorAtProperPosition() {
- if (mViewPager == null) {
- return null;
- }
-
- final int position = mViewPager.getCurrentItem();
- final Cursor cursor = mAdapter.getCursor();
-
- if (cursor == null) {
- return null;
- }
-
- cursor.moveToPosition(position);
-
- return cursor;
- }
-
- public Cursor getCursor() {
- return (mAdapter == null) ? null : mAdapter.getCursor();
- }
-
- @Override
- public void onMenuVisibilityChanged(boolean isVisible) {
- if (isVisible) {
- cancelActionBarHideRunnable();
- } else {
- postActionBarHideRunnableWithDelay();
- }
- }
-
- public void onNewPhotoLoaded() {
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/PhotoViewPager.java b/photoviewer/src/com/android/ex/photo/PhotoViewPager.java
deleted file mode 100644
index 65d1d6d..0000000
--- a/photoviewer/src/com/android/ex/photo/PhotoViewPager.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo;
-
-import android.content.Context;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * View pager for photo view fragments. Define our own class so we can specify the
- * view pager in XML.
- */
-public class PhotoViewPager extends ViewPager {
- /**
- * A type of intercept that should be performed
- */
- public static enum InterceptType { NONE, LEFT, RIGHT, BOTH }
-
- /**
- * Provides an ability to intercept touch events.
- * <p>
- * {@link ViewPager} intercepts all touch events and we need to be able to override this
- * behavior. Instead, we could perform a similar function by declaring a custom
- * {@link ViewGroup} to contain the pager and intercept touch events at a higher level.
- */
- public static interface OnInterceptTouchListener {
- /**
- * Called when a touch intercept is about to occur.
- *
- * @param origX the raw x coordinate of the initial touch
- * @param origY the raw y coordinate of the initial touch
- * @return Which type of touch, if any, should should be intercepted.
- */
- public InterceptType onTouchIntercept(float origX, float origY);
- }
-
- private static final int INVALID_POINTER = -1;
-
- private float mLastMotionX;
- private int mActivePointerId;
- /** The x coordinate where the touch originated */
- private float mActivatedX;
- /** The y coordinate where the touch originated */
- private float mActivatedY;
- private OnInterceptTouchListener mListener;
-
- public PhotoViewPager(Context context) {
- super(context);
- initialize();
- }
-
- public PhotoViewPager(Context context, AttributeSet attrs) {
- super(context, attrs);
- initialize();
- }
-
- private void initialize() {
- // Set the page transformer to perform the transition animation
- // for each page in the view.
- setPageTransformer(true, new PageTransformer() {
- @Override
- public void transformPage(View page, float position) {
-
- // The >= 1 is needed so that the page
- // (page A) that transitions behind the newly visible
- // page (page B) that comes in from the left does not
- // get the touch events because it is still on screen
- // (page A is still technically on screen despite being
- // invisible). This makes sure that when the transition
- // has completely finished, we revert it to its default
- // behavior and move it off of the screen.
- if (position < 0 || position >= 1.f) {
- page.setTranslationX(0);
- page.setAlpha(1.f);
- page.setScaleX(1);
- page.setScaleY(1);
- } else {
- page.setTranslationX(-position * page.getWidth());
- page.setAlpha(Math.max(0,1.f - position));
- final float scale = Math.max(0, 1.f - position * 0.3f);
- page.setScaleX(scale);
- page.setScaleY(scale);
- }
- }
- });
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * We intercept touch event intercepts so we can prevent switching views when the
- * current view is internally scrollable.
- */
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- final InterceptType intercept = (mListener != null)
- ? mListener.onTouchIntercept(mActivatedX, mActivatedY)
- : InterceptType.NONE;
- final boolean ignoreScrollLeft =
- (intercept == InterceptType.BOTH || intercept == InterceptType.LEFT);
- final boolean ignoreScrollRight =
- (intercept == InterceptType.BOTH || intercept == InterceptType.RIGHT);
-
- // Only check ability to page if we can't scroll in one / both directions
- final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
-
- if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
- mActivePointerId = INVALID_POINTER;
- }
-
- switch (action) {
- case MotionEvent.ACTION_MOVE: {
- if (ignoreScrollLeft || ignoreScrollRight) {
- final int activePointerId = mActivePointerId;
- if (activePointerId == INVALID_POINTER) {
- // If we don't have a valid id, the touch down wasn't on content.
- break;
- }
-
- final int pointerIndex =
- MotionEventCompat.findPointerIndex(ev, activePointerId);
- final float x = MotionEventCompat.getX(ev, pointerIndex);
-
- if (ignoreScrollLeft && ignoreScrollRight) {
- mLastMotionX = x;
- return false;
- } else if (ignoreScrollLeft && (x > mLastMotionX)) {
- mLastMotionX = x;
- return false;
- } else if (ignoreScrollRight && (x < mLastMotionX)) {
- mLastMotionX = x;
- return false;
- }
- }
- break;
- }
-
- case MotionEvent.ACTION_DOWN: {
- mLastMotionX = ev.getX();
- // Use the raw x/y as the children can be located anywhere and there isn't a
- // single offset that would be meaningful
- mActivatedX = ev.getRawX();
- mActivatedY = ev.getRawY();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- break;
- }
-
- case MotionEventCompat.ACTION_POINTER_UP: {
- final int pointerIndex = MotionEventCompat.getActionIndex(ev);
- final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
- if (pointerId == mActivePointerId) {
- // Our active pointer going up; select a new active pointer
- final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
- mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
- }
- break;
- }
- }
-
- return super.onInterceptTouchEvent(ev);
- }
-
- /**
- * sets the intercept touch listener.
- */
- public void setOnInterceptTouchListener(OnInterceptTouchListener l) {
- mListener = l;
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/adapters/BaseCursorPagerAdapter.java b/photoviewer/src/com/android/ex/photo/adapters/BaseCursorPagerAdapter.java
deleted file mode 100644
index 848d79a..0000000
--- a/photoviewer/src/com/android/ex/photo/adapters/BaseCursorPagerAdapter.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.adapters;
-
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.content.Context;
-import android.database.Cursor;
-import android.util.Log;
-import android.util.SparseIntArray;
-import android.view.View;
-
-import com.android.ex.photo.provider.PhotoContract;
-
-import java.util.HashMap;
-
-/**
- * Page adapter for use with an BaseCursorLoader. Unlike other cursor adapters, this has no
- * observers for automatic refresh. Instead, it depends upon external mechanisms to provide
- * the update signal.
- */
-public abstract class BaseCursorPagerAdapter extends BaseFragmentPagerAdapter {
- private static final String TAG = "BaseCursorPagerAdapter";
-
- Context mContext;
- private boolean mDataValid;
- private Cursor mCursor;
- private int mRowIDColumn;
- /** Mapping of row ID to cursor position */
- private SparseIntArray mItemPosition;
- /** Mapping of instantiated object to row ID */
- private HashMap<Object, Integer> mObjectRowMap = new HashMap<Object, Integer>();
-
- /**
- * Constructor that always enables auto-requery.
- *
- * @param c The cursor from which to get the data.
- * @param context The context
- */
- public BaseCursorPagerAdapter(Context context, FragmentManager fm, Cursor c) {
- super(fm);
- init(context, c);
- }
-
- /**
- * Makes a fragment for the data pointed to by the cursor
- *
- * @param context Interface to application's global information
- * @param cursor The cursor from which to get the data. The cursor is already
- * moved to the correct position.
- * @return the newly created fragment.
- */
- public abstract Fragment getItem(Context context, Cursor cursor, int position);
-
- @Override
- public Fragment getItem(int position) {
- if (mDataValid && moveCursorTo(position)) {
- return getItem(mContext, mCursor, position);
- }
- return null;
- }
-
- @Override
- public int getCount() {
- if (mDataValid && mCursor != null) {
- return mCursor.getCount();
- } else {
- return 0;
- }
- }
-
- @Override
- public Object instantiateItem(View container, int position) {
- if (!mDataValid) {
- throw new IllegalStateException("this should only be called when the cursor is valid");
- }
-
- final Integer rowId;
- if (moveCursorTo(position)) {
- rowId = mCursor.getString(mRowIDColumn).hashCode();
- } else {
- rowId = null;
- }
-
- // Create the fragment and bind cursor data
- final Object obj = super.instantiateItem(container, position);
- if (obj != null) {
- mObjectRowMap.put(obj, rowId);
- }
- return obj;
- }
-
- @Override
- public void destroyItem(View container, int position, Object object) {
- mObjectRowMap.remove(object);
-
- super.destroyItem(container, position, object);
- }
-
- @Override
- public int getItemPosition(Object object) {
- final Integer rowId = mObjectRowMap.get(object);
- if (rowId == null || mItemPosition == null) {
- return POSITION_NONE;
- }
-
- final int position = mItemPosition.get(rowId, POSITION_NONE);
- return position;
- }
-
- /**
- * @return true if data is valid
- */
- public boolean isDataValid() {
- return mDataValid;
- }
-
- /**
- * Returns the cursor.
- */
- public Cursor getCursor() {
- return mCursor;
- }
-
- /**
- * Returns the data item associated with the specified position in the data set.
- */
- public Object getDataItem(int position) {
- if (mDataValid && moveCursorTo(position)) {
- return mCursor;
- } else {
- return null;
- }
- }
-
- /**
- * Returns the row id associated with the specified position in the list.
- */
- public long getItemId(int position) {
- if (mDataValid && moveCursorTo(position)) {
- return mCursor.getString(mRowIDColumn).hashCode();
- } else {
- return 0;
- }
- }
-
- /**
- * Swap in a new Cursor, returning the old Cursor.
- *
- * @param newCursor The new cursor to be used.
- * @return Returns the previously set Cursor, or null if there was not one.
- * If the given new Cursor is the same instance is the previously set
- * Cursor, null is also returned.
- */
- public Cursor swapCursor(Cursor newCursor) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "swapCursor old=" + (mCursor == null ? -1 : mCursor.getCount()) +
- "; new=" + (newCursor == null ? -1 : newCursor.getCount()));
- }
-
- if (newCursor == mCursor) {
- return null;
- }
- Cursor oldCursor = mCursor;
- mCursor = newCursor;
- if (newCursor != null) {
- mRowIDColumn = newCursor.getColumnIndex(PhotoContract.PhotoViewColumns.URI);
- mDataValid = true;
- } else {
- mRowIDColumn = -1;
- mDataValid = false;
- }
-
- setItemPosition();
- notifyDataSetChanged(); // notify the observers about the new cursor
- return oldCursor;
- }
-
- /**
- * Converts the cursor into a CharSequence. Subclasses should override this
- * method to convert their results. The default implementation returns an
- * empty String for null values or the default String representation of
- * the value.
- *
- * @param cursor the cursor to convert to a CharSequence
- * @return a CharSequence representing the value
- */
- public CharSequence convertToString(Cursor cursor) {
- return cursor == null ? "" : cursor.toString();
- }
-
- @Override
- protected String makeFragmentName(int viewId, int index) {
- if (moveCursorTo(index)) {
- return "android:pager:" + viewId + ":" + mCursor.getString(mRowIDColumn).hashCode();
- } else {
- return super.makeFragmentName(viewId, index);
- }
- }
-
- /**
- * Moves the cursor to the given position
- *
- * @return {@code true} if the cursor's position was set. Otherwise, {@code false}.
- */
- private boolean moveCursorTo(int position) {
- if (mCursor != null && !mCursor.isClosed()) {
- return mCursor.moveToPosition(position);
- }
- return false;
- }
-
- /**
- * Initialize the adapter.
- */
- private void init(Context context, Cursor c) {
- boolean cursorPresent = c != null;
- mCursor = c;
- mDataValid = cursorPresent;
- mContext = context;
- mRowIDColumn = cursorPresent
- ? mCursor.getColumnIndex(PhotoContract.PhotoViewColumns.URI) : -1;
- }
-
- /**
- * Sets the {@link #mItemPosition} instance variable with the current mapping of
- * row id to cursor position.
- */
- private void setItemPosition() {
- if (!mDataValid || mCursor == null || mCursor.isClosed()) {
- mItemPosition = null;
- return;
- }
-
- SparseIntArray itemPosition = new SparseIntArray(mCursor.getCount());
-
- mCursor.moveToPosition(-1);
- while (mCursor.moveToNext()) {
- final int rowId = mCursor.getString(mRowIDColumn).hashCode();
- final int position = mCursor.getPosition();
-
- itemPosition.append(rowId, position);
- }
- mItemPosition = itemPosition;
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/adapters/BaseFragmentPagerAdapter.java b/photoviewer/src/com/android/ex/photo/adapters/BaseFragmentPagerAdapter.java
deleted file mode 100644
index 9c24575..0000000
--- a/photoviewer/src/com/android/ex/photo/adapters/BaseFragmentPagerAdapter.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.adapters;
-
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.os.Parcelable;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.support.v4.view.PagerAdapter;
-import android.util.Log;
-import android.util.LruCache;
-import android.view.View;
-
-/**
- * NOTE: This is a direct copy of {@link FragmentPagerAdapter} with four very important
- * modifications.
- * <p>
- * <ol>
- * <li>The method {@link #makeFragmentName(int, int)} is declared "protected"
- * in our class. We need to be able to re-define the fragment's name according to data
- * only available to sub-classes.</li>
- * <li>The method {@link #isViewFromObject(View, Object)} has been reimplemented to search
- * the entire view hierarchy for the given view.</li>
- * <li>In method {@link #destroyItem(View, int, Object)}, the fragment is detached and
- * added to a cache. If the fragment is evicted from the cache, it will be deleted.
- * An album may contain thousands of photos and we want to avoid having thousands of
- * fragments.</li>
- * </ol>
- */
-public abstract class BaseFragmentPagerAdapter extends PagerAdapter {
- /** The default size of {@link #mFragmentCache} */
- private static final int DEFAULT_CACHE_SIZE = 5;
- private static final String TAG = "FragmentPagerAdapter";
- private static final boolean DEBUG = false;
-
- private final FragmentManager mFragmentManager;
- private FragmentTransaction mCurTransaction = null;
- private Fragment mCurrentPrimaryItem = null;
- /** A cache to store detached fragments before they are removed */
- private LruCache<String, Fragment> mFragmentCache = new FragmentCache(DEFAULT_CACHE_SIZE);
-
- public BaseFragmentPagerAdapter(FragmentManager fm) {
- mFragmentManager = fm;
- }
-
- /**
- * Return the Fragment associated with a specified position.
- */
- public abstract Fragment getItem(int position);
-
- @Override
- public void startUpdate(View container) {
- }
-
- @Override
- public Object instantiateItem(View container, int position) {
- if (mCurTransaction == null) {
- mCurTransaction = mFragmentManager.beginTransaction();
- }
-
- // Do we already have this fragment?
- String name = makeFragmentName(container.getId(), position);
-
- // Remove item from the cache
- mFragmentCache.remove(name);
-
- Fragment fragment = mFragmentManager.findFragmentByTag(name);
- if (fragment != null) {
- if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment);
- mCurTransaction.attach(fragment);
- } else {
- fragment = getItem(position);
- if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
- mCurTransaction.add(container.getId(), fragment,
- makeFragmentName(container.getId(), position));
- }
- if (fragment != mCurrentPrimaryItem) {
- fragment.setMenuVisibility(false);
- }
-
- return fragment;
- }
-
- @Override
- public void destroyItem(View container, int position, Object object) {
- if (mCurTransaction == null) {
- mCurTransaction = mFragmentManager.beginTransaction();
- }
- if (DEBUG) Log.v(TAG, "Detaching item #" + position + ": f=" + object
- + " v=" + ((Fragment)object).getView());
-
- Fragment fragment = (Fragment) object;
- String name = fragment.getTag();
- if (name == null) {
- // We prefer to get the name directly from the fragment, but, if the fragment is
- // detached before the add transaction is committed, this could be 'null'. In
- // that case, generate a name so we can still cache the fragment.
- name = makeFragmentName(container.getId(), position);
- }
-
- mFragmentCache.put(name, fragment);
- mCurTransaction.detach(fragment);
- }
-
- @Override
- public void setPrimaryItem(View container, int position, Object object) {
- Fragment fragment = (Fragment) object;
- if (fragment != mCurrentPrimaryItem) {
- if (mCurrentPrimaryItem != null) {
- mCurrentPrimaryItem.setMenuVisibility(false);
- }
- if (fragment != null) {
- fragment.setMenuVisibility(true);
- }
- mCurrentPrimaryItem = fragment;
- }
-
- }
-
- @Override
- public void finishUpdate(View container) {
- if (mCurTransaction != null) {
- mCurTransaction.commitAllowingStateLoss();
- mCurTransaction = null;
- mFragmentManager.executePendingTransactions();
- }
- }
-
- @Override
- public boolean isViewFromObject(View view, Object object) {
- // Ascend the tree to determine if the view is a child of the fragment
- View root = ((Fragment) object).getView();
- for (Object v = view; v instanceof View; v = ((View) v).getParent()) {
- if (v == root) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public Parcelable saveState() {
- return null;
- }
-
- @Override
- public void restoreState(Parcelable state, ClassLoader loader) {
- }
-
- /** Creates a name for the fragment */
- protected String makeFragmentName(int viewId, int index) {
- return "android:switcher:" + viewId + ":" + index;
- }
-
- /**
- * A cache of detached fragments.
- */
- private class FragmentCache extends LruCache<String, Fragment> {
- public FragmentCache(int size) {
- super(size);
- }
-
- @Override
- protected void entryRemoved(boolean evicted, String key,
- Fragment oldValue, Fragment newValue) {
- // remove the fragment if it's evicted OR it's replaced by a new fragment
- if (evicted || (newValue != null && oldValue != newValue)) {
- mCurTransaction.remove(oldValue);
- }
- }
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/adapters/PhotoPagerAdapter.java b/photoviewer/src/com/android/ex/photo/adapters/PhotoPagerAdapter.java
deleted file mode 100644
index bf75ecb..0000000
--- a/photoviewer/src/com/android/ex/photo/adapters/PhotoPagerAdapter.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.adapters;
-
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.content.Context;
-import android.database.Cursor;
-
-import com.android.ex.photo.Intents;
-import com.android.ex.photo.Intents.PhotoViewIntentBuilder;
-import com.android.ex.photo.fragments.PhotoViewFragment;
-import com.android.ex.photo.provider.PhotoContract;
-
-/**
- * Pager adapter for the photo view
- */
-public class PhotoPagerAdapter extends BaseCursorPagerAdapter {
- private int mContentUriIndex;
- private int mThumbnailUriIndex;
-
- public PhotoPagerAdapter(Context context, FragmentManager fm, Cursor c) {
- super(context, fm, c);
- }
-
- @Override
- public Fragment getItem(Context context, Cursor cursor, int position) {
- final String photoUri = cursor.getString(mContentUriIndex);
- final String thumbnailUri = cursor.getString(mThumbnailUriIndex);
-
- // create new PhotoViewFragment
- final PhotoViewIntentBuilder builder =
- Intents.newPhotoViewFragmentIntentBuilder(mContext);
- builder
- .setResolvedPhotoUri(photoUri)
- .setThumbnailUri(thumbnailUri);
-
- return new PhotoViewFragment(builder.build(), position, this);
- }
-
- @Override
- public Cursor swapCursor(Cursor newCursor) {
- if (newCursor != null) {
- mContentUriIndex =
- newCursor.getColumnIndex(PhotoContract.PhotoViewColumns.CONTENT_URI);
- mThumbnailUriIndex =
- newCursor.getColumnIndex(PhotoContract.PhotoViewColumns.THUMBNAIL_URI);
- } else {
- mContentUriIndex = -1;
- mThumbnailUriIndex = -1;
- }
-
- return super.swapCursor(newCursor);
- }
-
- public String getPhotoUri(Cursor cursor) {
- return cursor.getString(mContentUriIndex);
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java
deleted file mode 100644
index efb8145..0000000
--- a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.fragments;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.LoaderManager;
-import android.app.LoaderManager.LoaderCallbacks;
-import android.content.Context;
-import android.content.Intent;
-import android.content.Loader;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import com.android.ex.photo.Intents;
-import com.android.ex.photo.PhotoViewActivity;
-import com.android.ex.photo.PhotoViewActivity.CursorChangedListener;
-import com.android.ex.photo.PhotoViewActivity.OnScreenListener;
-import com.android.ex.photo.R;
-import com.android.ex.photo.adapters.PhotoPagerAdapter;
-import com.android.ex.photo.loaders.PhotoBitmapLoader;
-import com.android.ex.photo.util.ImageUtils;
-import com.android.ex.photo.views.PhotoView;
-import com.android.ex.photo.views.ProgressBarWrapper;
-
-/**
- * Displays a photo.
- */
-public class PhotoViewFragment extends Fragment implements
- LoaderCallbacks<Bitmap>, OnClickListener, OnScreenListener, CursorChangedListener {
- /**
- * Interface for components that are internally scrollable left-to-right.
- */
- public static interface HorizontallyScrollable {
- /**
- * Return {@code true} if the component needs to receive right-to-left
- * touch movements.
- *
- * @param origX the raw x coordinate of the initial touch
- * @param origY the raw y coordinate of the initial touch
- */
-
- public boolean interceptMoveLeft(float origX, float origY);
-
- /**
- * Return {@code true} if the component needs to receive left-to-right
- * touch movements.
- *
- * @param origX the raw x coordinate of the initial touch
- * @param origY the raw y coordinate of the initial touch
- */
- public boolean interceptMoveRight(float origX, float origY);
- }
-
- private final static String STATE_INTENT_KEY =
- "com.android.mail.photo.fragments.PhotoViewFragment.INTENT";
-
- // Loader IDs
- private final static int LOADER_ID_PHOTO = 1;
- private final static int LOADER_ID_THUMBNAIL = 2;
-
- /** The size of the photo */
- public static Integer sPhotoSize;
-
- /** The URL of a photo to display */
- private String mResolvedPhotoUri;
- private String mThumbnailUri;
- /** The intent we were launched with */
- private Intent mIntent;
- private PhotoViewActivity mCallback;
- private PhotoPagerAdapter mAdapter;
-
- private PhotoView mPhotoView;
- private ImageView mPhotoPreviewImage;
- private TextView mEmptyText;
- private ImageView mRetryButton;
- private ProgressBarWrapper mPhotoProgressBar;
-
- private final int mPosition;
-
- /** Whether or not the fragment should make the photo full-screen */
- private boolean mFullScreen;
-
- /** Whether or not the progress bar is showing valid information about the progress stated */
- private boolean mProgressBarNeeded = true;
-
- private View mPhotoPreviewAndProgress;
-
- public PhotoViewFragment() {
- mPosition = -1;
- mProgressBarNeeded = true;
- }
-
- public PhotoViewFragment(Intent intent, int position, PhotoPagerAdapter adapter) {
- mIntent = intent;
- mPosition = position;
- mAdapter = adapter;
- mProgressBarNeeded = true;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- mCallback = (PhotoViewActivity) activity;
- if (mCallback == null) {
- throw new IllegalArgumentException(
- "Activity must be a derived class of PhotoViewActivity");
- }
-
- if (sPhotoSize == null) {
- final DisplayMetrics metrics = new DisplayMetrics();
- final WindowManager wm =
- (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
- final ImageUtils.ImageSize imageSize = ImageUtils.sUseImageSize;
- wm.getDefaultDisplay().getMetrics(metrics);
- switch (imageSize) {
- case EXTRA_SMALL: {
- // Use a photo that's 80% of the "small" size
- sPhotoSize = (Math.min(metrics.heightPixels, metrics.widthPixels) * 800) / 1000;
- break;
- }
-
- case SMALL:
- case NORMAL:
- default: {
- sPhotoSize = Math.min(metrics.heightPixels, metrics.widthPixels);
- break;
- }
- }
- }
- }
-
- @Override
- public void onDetach() {
- mCallback = null;
- super.onDetach();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (savedInstanceState != null) {
- final Bundle state = savedInstanceState.getBundle(STATE_INTENT_KEY);
- if (state != null) {
- mIntent = new Intent().putExtras(state);
- }
- }
-
- if (mIntent != null) {
- mResolvedPhotoUri = mIntent.getStringExtra(Intents.EXTRA_RESOLVED_PHOTO_URI);
- mThumbnailUri = mIntent.getStringExtra(Intents.EXTRA_THUMBNAIL_URI);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View view = inflater.inflate(R.layout.photo_fragment_view, container, false);
-
- mPhotoView = (PhotoView) view.findViewById(R.id.photo_view);
- mPhotoView.setOnClickListener(this);
- mPhotoView.setFullScreen(mFullScreen, false);
- mPhotoView.enableImageTransforms(true);
-
- mPhotoPreviewAndProgress = view.findViewById(R.id.photo_preview);
- mPhotoPreviewImage = (ImageView) view.findViewById(R.id.photo_preview_image);
- final ProgressBar indeterminate =
- (ProgressBar) view.findViewById(R.id.indeterminate_progress);
- final ProgressBar determinate =
- (ProgressBar) view.findViewById(R.id.determinate_progress);
- mPhotoProgressBar = new ProgressBarWrapper(determinate, indeterminate, true);
- mEmptyText = (TextView) view.findViewById(R.id.empty_text);
- mRetryButton = (ImageView) view.findViewById(R.id.retry_button);
-
- // Don't call until we've setup the entire view
- setViewVisibility();
-
- return view;
- }
-
- @Override
- public void onResume() {
- mCallback.addScreenListener(this);
- mCallback.addCursorListener(this);
-
- getLoaderManager().initLoader(LOADER_ID_THUMBNAIL, null, this);
-
- super.onResume();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- // Remove listeners
- mCallback.removeCursorListener(this);
- mCallback.removeScreenListener(this);
- resetPhotoView();
- }
-
- @Override
- public void onDestroyView() {
- // Clean up views and other components
- if (mPhotoView != null) {
- mPhotoView.clear();
- mPhotoView = null;
- }
-
- super.onDestroyView();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
-
- if (mIntent != null) {
- outState.putParcelable(STATE_INTENT_KEY, mIntent.getExtras());
- }
- }
-
- @Override
- public Loader<Bitmap> onCreateLoader(int id, Bundle args) {
- switch (id) {
- case LOADER_ID_PHOTO:
- return new PhotoBitmapLoader(getActivity(), mResolvedPhotoUri);
- case LOADER_ID_THUMBNAIL:
- return new PhotoBitmapLoader(getActivity(), mThumbnailUri);
- default:
- return null;
- }
- }
-
- @Override
- public void onLoadFinished(Loader<Bitmap> loader, Bitmap data) {
- // If we don't have a view, the fragment has been paused. We'll get the cursor again later.
- if (getView() == null) {
- return;
- }
-
- final int id = loader.getId();
- switch (id) {
- case LOADER_ID_PHOTO:
- if (data != null) {
- bindPhoto(data);
- mPhotoPreviewAndProgress.setVisibility(View.GONE);
- mProgressBarNeeded = false;
- }
- break;
- case LOADER_ID_THUMBNAIL:
- if (isPhotoBound()) {
- // There is need to do anything with the thumbnail image, as the full size
- // image is being shown.
- mPhotoPreviewAndProgress.setVisibility(View.GONE);
- mProgressBarNeeded = false;
- return;
- } else {
- // Make the preview image view visible
- mPhotoPreviewImage.setVisibility(View.VISIBLE);
-
- if (data == null) {
- // no preview, show default
- mPhotoPreviewImage.setImageResource(R.drawable.default_image);
- mPhotoPreviewImage.setScaleType(ImageView.ScaleType.CENTER);
- } else {
- // Show the preview
- mPhotoPreviewImage.setImageBitmap(data);
- }
- // Now load the full size image
- getLoaderManager().initLoader(LOADER_ID_PHOTO, null, this);
- }
- break;
- default:
- break;
- }
-
- if (mProgressBarNeeded == false) {
- // Hide the progress bar as it isn't needed anymore.
- mPhotoProgressBar.setVisibility(View.GONE);
- }
- if (data != null) {
- mCallback.onNewPhotoLoaded();
- }
-
- setViewVisibility();
- }
-
- /**
- * Binds an image to the photo view.
- */
- private void bindPhoto(Bitmap bitmap) {
- if (mPhotoView != null) {
- mPhotoView.bindPhoto(bitmap);
- }
- }
-
- /**
- * Resets the photo view to it's default state w/ no bound photo.
- */
- private void resetPhotoView() {
- if (mPhotoView != null) {
- mPhotoView.bindPhoto(null);
- }
- }
-
- @Override
- public void onLoaderReset(Loader<Bitmap> loader) {
- // Do nothing
- }
-
- @Override
- public void onClick(View v) {
- mCallback.toggleFullScreen();
- }
-
- @Override
- public void onFullScreenChanged(boolean fullScreen) {
- setViewVisibility();
- }
-
- @Override
- public void onViewActivated() {
- if (!mCallback.isFragmentActive(this)) {
- // we're not in the foreground; reset our view
- resetViews();
- } else {
- if (!isPhotoBound()) {
- // Restart the loader
- getLoaderManager().restartLoader(LOADER_ID_THUMBNAIL, null, this);
- }
- mCallback.onFragmentVisible(this);
- }
- }
-
- /**
- * Reset the views to their default states
- */
- public void resetViews() {
- if (mPhotoView != null) {
- mPhotoView.resetTransformations();
- }
- }
-
- @Override
- public boolean onInterceptMoveLeft(float origX, float origY) {
- if (!mCallback.isFragmentActive(this)) {
- // we're not in the foreground; don't intercept any touches
- return false;
- }
-
- return (mPhotoView != null && mPhotoView.interceptMoveLeft(origX, origY));
- }
-
- @Override
- public boolean onInterceptMoveRight(float origX, float origY) {
- if (!mCallback.isFragmentActive(this)) {
- // we're not in the foreground; don't intercept any touches
- return false;
- }
-
- return (mPhotoView != null && mPhotoView.interceptMoveRight(origX, origY));
- }
-
- /**
- * Returns {@code true} if a photo has been bound. Otherwise, returns {@code false}.
- */
- public boolean isPhotoBound() {
- return (mPhotoView != null && mPhotoView.isPhotoBound());
- }
-
- /**
- * Sets view visibility depending upon whether or not we're in "full screen" mode.
- */
- private void setViewVisibility() {
- final boolean fullScreen = mCallback.isFragmentFullScreen(this);
- final boolean hide = fullScreen;
-
- setFullScreen(hide);
- }
-
- /**
- * Sets full-screen mode for the views.
- */
- public void setFullScreen(boolean fullScreen) {
- mFullScreen = fullScreen;
- }
-
- @Override
- public void onCursorChanged(Cursor cursor) {
- if (cursor.moveToPosition(mPosition) && !isPhotoBound()) {
- final LoaderManager manager = getLoaderManager();
- final Loader<Bitmap> fakeLoader = manager.getLoader(LOADER_ID_PHOTO);
- if (fakeLoader == null) {
- return;
- }
-
- final PhotoBitmapLoader loader =
- (PhotoBitmapLoader) fakeLoader;
- mResolvedPhotoUri = mAdapter.getPhotoUri(cursor);
- loader.setPhotoUri(mResolvedPhotoUri);
- loader.forceLoad();
- }
- }
-
- public ProgressBarWrapper getPhotoProgressBar() {
- return mPhotoProgressBar;
- }
-
- public TextView getEmptyText() {
- return mEmptyText;
- }
-
- public ImageView getRetryButton() {
- return mRetryButton;
- }
-
- public boolean isProgressBarNeeded() {
- return mProgressBarNeeded;
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/loaders/PhotoBitmapLoader.java b/photoviewer/src/com/android/ex/photo/loaders/PhotoBitmapLoader.java
deleted file mode 100644
index fe42e0d..0000000
--- a/photoviewer/src/com/android/ex/photo/loaders/PhotoBitmapLoader.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.loaders;
-
-import android.content.AsyncTaskLoader;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.util.DisplayMetrics;
-
-import com.android.ex.photo.fragments.PhotoViewFragment;
-import com.android.ex.photo.util.ImageUtils;
-
-/**
- * Loader for the bitmap of a photo.
- */
-public class PhotoBitmapLoader extends AsyncTaskLoader<Bitmap> {
- private String mPhotoUri;
-
- private Bitmap mBitmap;
-
- public PhotoBitmapLoader(Context context, String photoUri) {
- super(context);
- mPhotoUri = photoUri;
- }
-
- public void setPhotoUri(String photoUri) {
- mPhotoUri = photoUri;
- }
-
- @Override
- public Bitmap loadInBackground() {
- Context context = getContext();
-
- if (context != null && mPhotoUri != null) {
- final ContentResolver resolver = context.getContentResolver();
- Bitmap bitmap = ImageUtils.createLocalBitmap(resolver, Uri.parse(mPhotoUri),
- PhotoViewFragment.sPhotoSize);
- if (bitmap != null) {
- bitmap.setDensity(DisplayMetrics.DENSITY_MEDIUM);
- }
- return bitmap;
- }
-
- return null;
- }
-
- /**
- * Called when there is new data to deliver to the client. The
- * super class will take care of delivering it; the implementation
- * here just adds a little more logic.
- */
- @Override
- public void deliverResult(Bitmap bitmap) {
- if (isReset()) {
- // An async query came in while the loader is stopped. We
- // don't need the result.
- if (bitmap != null) {
- onReleaseResources(bitmap);
- }
- }
- Bitmap oldBitmap = mBitmap;
- mBitmap = bitmap;
-
- if (isStarted()) {
- // If the Loader is currently started, we can immediately
- // deliver its results.
- super.deliverResult(bitmap);
- }
-
- // At this point we can release the resources associated with
- // 'oldBitmap' if needed; now that the new result is delivered we
- // know that it is no longer in use.
- if (oldBitmap != null && oldBitmap != bitmap && !oldBitmap.isRecycled()) {
- onReleaseResources(oldBitmap);
- }
- }
-
- /**
- * Handles a request to start the Loader.
- */
- @Override
- protected void onStartLoading() {
- if (mBitmap != null) {
- // If we currently have a result available, deliver it
- // immediately.
- deliverResult(mBitmap);
- }
-
- if (takeContentChanged() || mBitmap == null) {
- // If the data has changed since the last time it was loaded
- // or is not currently available, start a load.
- forceLoad();
- }
- }
-
- /**
- * Handles a request to stop the Loader.
- */
- @Override protected void onStopLoading() {
- // Attempt to cancel the current load task if possible.
- cancelLoad();
- }
-
- /**
- * Handles a request to cancel a load.
- */
- @Override
- public void onCanceled(Bitmap bitmap) {
- super.onCanceled(bitmap);
-
- // At this point we can release the resources associated with 'bitmap'
- // if needed.
- onReleaseResources(bitmap);
- }
-
- /**
- * Handles a request to completely reset the Loader.
- */
- @Override
- protected void onReset() {
- super.onReset();
-
- // Ensure the loader is stopped
- onStopLoading();
-
- // At this point we can release the resources associated with 'bitmap'
- // if needed.
- if (mBitmap != null) {
- onReleaseResources(mBitmap);
- mBitmap = null;
- }
- }
-
- /**
- * Helper function to take care of releasing resources associated
- * with an actively loaded data set.
- */
- protected void onReleaseResources(Bitmap bitmap) {
- if (bitmap != null && !bitmap.isRecycled()) {
- bitmap.recycle();
- }
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/loaders/PhotoPagerLoader.java b/photoviewer/src/com/android/ex/photo/loaders/PhotoPagerLoader.java
deleted file mode 100644
index 7ba932b..0000000
--- a/photoviewer/src/com/android/ex/photo/loaders/PhotoPagerLoader.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.loaders;
-
-import android.content.Context;
-import android.content.CursorLoader;
-import android.database.Cursor;
-import android.net.Uri;
-
-import com.android.ex.photo.provider.PhotoContract;
-
-/**
- * Loader for a set of photo IDs.
- */
-public class PhotoPagerLoader extends CursorLoader {
- private final Uri mPhotosUri;
- private final String[] mProjection;
-
- public PhotoPagerLoader(
- Context context, Uri photosUri, String[] projection) {
- super(context);
- mPhotosUri = photosUri;
- mProjection = projection != null ? projection : PhotoContract.PhotoQuery.PROJECTION;
- }
-
- @Override
- public Cursor loadInBackground() {
- Cursor returnCursor = null;
-
- final Uri loaderUri = mPhotosUri.buildUpon().appendQueryParameter(
- PhotoContract.ContentTypeParameters.CONTENT_TYPE, "image/").build();
- setUri(loaderUri);
- setProjection(mProjection);
- returnCursor = super.loadInBackground();
-
- return returnCursor;
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/provider/PhotoContract.java b/photoviewer/src/com/android/ex/photo/provider/PhotoContract.java
deleted file mode 100644
index 439b68b..0000000
--- a/photoviewer/src/com/android/ex/photo/provider/PhotoContract.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.provider;
-
-import android.net.Uri;
-import android.provider.OpenableColumns;
-
-public final class PhotoContract {
- /** Columns for the view */
- public static interface PhotoViewColumns {
- /**
- * This column is a {@link Uri} that can be queried
- * for this individual image (resulting cursor has one single row for this image).
- */
- public static final String URI = "uri";
- /**
- * This column is a {@link String} that can be queried for this
- * individual image to return a displayable name.
- */
- public static final String NAME = OpenableColumns.DISPLAY_NAME;
- /**
- * This column is a {@link Uri} that points to the downloaded local file.
- * Can be null.
- */
- public static final String CONTENT_URI = "contentUri";
- /**
- * This column is a {@link Uri} that points to a thumbnail of the image
- * that ideally is a local file.
- * Can be null.
- */
- public static final String THUMBNAIL_URI = "thumbnailUri";
- /**
- * This string column is the MIME type.
- */
- public static final String CONTENT_TYPE = "contentType";
-
- }
-
- public static interface PhotoQuery {
- /** Projection of the returned cursor */
- public final static String[] PROJECTION = {
- PhotoViewColumns.URI,
- PhotoViewColumns.NAME,
- PhotoViewColumns.CONTENT_URI,
- PhotoViewColumns.THUMBNAIL_URI,
- PhotoViewColumns.CONTENT_TYPE,
- };
- }
-
- public static final class ContentTypeParameters {
- /**
- * Parameter used to specify which type of content to return.
- * Allows multiple types to be specified.
- */
- public static final String CONTENT_TYPE = "contentType";
-
- private ContentTypeParameters() {}
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/util/Exif.java b/photoviewer/src/com/android/ex/photo/util/Exif.java
deleted file mode 100644
index 743b896..0000000
--- a/photoviewer/src/com/android/ex/photo/util/Exif.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * 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.android.ex.photo.util;
-
-import android.util.Log;
-
-public class Exif {
- private static final String TAG = "CameraExif";
-
- // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
- public static int getOrientation(byte[] jpeg) {
- if (jpeg == null) {
- return 0;
- }
-
- int offset = 0;
- int length = 0;
-
- // ISO/IEC 10918-1:1993(E)
- while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
- int marker = jpeg[offset] & 0xFF;
-
- // Check if the marker is a padding.
- if (marker == 0xFF) {
- continue;
- }
- offset++;
-
- // Check if the marker is SOI or TEM.
- if (marker == 0xD8 || marker == 0x01) {
- continue;
- }
- // Check if the marker is EOI or SOS.
- if (marker == 0xD9 || marker == 0xDA) {
- break;
- }
-
- // Get the length and check if it is reasonable.
- length = pack(jpeg, offset, 2, false);
- if (length < 2 || offset + length > jpeg.length) {
- Log.e(TAG, "Invalid length");
- return 0;
- }
-
- // Break if the marker is EXIF in APP1.
- if (marker == 0xE1 && length >= 8 &&
- pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
- pack(jpeg, offset + 6, 2, false) == 0) {
- offset += 8;
- length -= 8;
- break;
- }
-
- // Skip other markers.
- offset += length;
- length = 0;
- }
-
- // JEITA CP-3451 Exif Version 2.2
- if (length > 8) {
- // Identify the byte order.
- int tag = pack(jpeg, offset, 4, false);
- if (tag != 0x49492A00 && tag != 0x4D4D002A) {
- Log.e(TAG, "Invalid byte order");
- return 0;
- }
- boolean littleEndian = (tag == 0x49492A00);
-
- // Get the offset and check if it is reasonable.
- int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
- if (count < 10 || count > length) {
- Log.e(TAG, "Invalid offset");
- return 0;
- }
- offset += count;
- length -= count;
-
- // Get the count and go through all the elements.
- count = pack(jpeg, offset - 2, 2, littleEndian);
- while (count-- > 0 && length >= 12) {
- // Get the tag and check if it is orientation.
- tag = pack(jpeg, offset, 2, littleEndian);
- if (tag == 0x0112) {
- // We do not really care about type and count, do we?
- int orientation = pack(jpeg, offset + 8, 2, littleEndian);
- switch (orientation) {
- case 1:
- return 0;
- case 3:
- return 180;
- case 6:
- return 90;
- case 8:
- return 270;
- }
- Log.i(TAG, "Unsupported orientation");
- return 0;
- }
- offset += 12;
- length -= 12;
- }
- }
-
- Log.i(TAG, "Orientation not found");
- return 0;
- }
-
- private static int pack(byte[] bytes, int offset, int length,
- boolean littleEndian) {
- int step = 1;
- if (littleEndian) {
- offset += length - 1;
- step = -1;
- }
-
- int value = 0;
- while (length-- > 0) {
- value = (value << 8) | (bytes[offset] & 0xFF);
- offset += step;
- }
- return value;
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/util/ImageUtils.java b/photoviewer/src/com/android/ex/photo/util/ImageUtils.java
deleted file mode 100644
index 7fe971a..0000000
--- a/photoviewer/src/com/android/ex/photo/util/ImageUtils.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.util;
-
-import android.content.ContentResolver;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Matrix;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.util.Log;
-
-import com.android.ex.photo.PhotoViewActivity;
-import com.android.ex.photo.util.Exif;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Image utilities
- */
-public class ImageUtils {
- // Logging
- private static final String TAG = "ImageUtils";
-
- /** Minimum class memory class to use full-res photos */
- private final static long MIN_NORMAL_CLASS = 32;
- /** Minimum class memory class to use small photos */
- private final static long MIN_SMALL_CLASS = 24;
-
- public static enum ImageSize {
- EXTRA_SMALL,
- SMALL,
- NORMAL,
- }
-
- public static final ImageSize sUseImageSize;
- static {
- // On HC and beyond, assume devices are more capable
- if (Build.VERSION.SDK_INT >= 11) {
- sUseImageSize = ImageSize.NORMAL;
- } else {
- if (PhotoViewActivity.sMemoryClass >= MIN_NORMAL_CLASS) {
- // We have plenty of memory; use full sized photos
- sUseImageSize = ImageSize.NORMAL;
- } else if (PhotoViewActivity.sMemoryClass >= MIN_SMALL_CLASS) {
- // We have slight less memory; use smaller sized photos
- sUseImageSize = ImageSize.SMALL;
- } else {
- // We have little memory; use very small sized photos
- sUseImageSize = ImageSize.EXTRA_SMALL;
- }
- }
- }
-
- /**
- * @return true if the MimeType type is image
- */
- public static boolean isImageMimeType(String mimeType) {
- return mimeType != null && mimeType.startsWith("image/");
- }
-
- /**
- * Create a bitmap from a local URI
- *
- * @param resolver The ContentResolver
- * @param uri The local URI
- * @param maxSize The maximum size (either width or height)
- *
- * @return The new bitmap or null
- */
- public static Bitmap createLocalBitmap(ContentResolver resolver, Uri uri, int maxSize) {
- InputStream inputStream = null;
- try {
- final BitmapFactory.Options opts = new BitmapFactory.Options();
- final Point bounds = getImageBounds(resolver, uri);
-
- inputStream = resolver.openInputStream(uri);
- opts.inSampleSize = Math.max(bounds.x / maxSize, bounds.y / maxSize);
-
- final Bitmap decodedBitmap = decodeStream(inputStream, null, opts);
-
- // Correct thumbnail orientation as necessary
- // TODO: Fix rotation if it's actually a problem
- //return rotateBitmap(resolver, uri, decodedBitmap);
- return decodedBitmap;
-
- } catch (FileNotFoundException exception) {
- // Do nothing - the photo will appear to be missing
- } catch (IOException exception) {
- // Do nothing - the photo will appear to be missing
- } catch (IllegalArgumentException exception) {
- // Do nothing - the photo will appear to be missing
- } finally {
- try {
- if (inputStream != null) {
- inputStream.close();
- }
- } catch (IOException ignore) {
- }
- }
- return null;
- }
-
- /**
- * Wrapper around {@link BitmapFactory#decodeStream(InputStream, Rect,
- * BitmapFactory.Options)} that returns {@code null} on {@link
- * OutOfMemoryError}.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts) {
- ByteArrayOutputStream out = null;
- try {
- out = new ByteArrayOutputStream();
- final byte[] buffer = new byte[4096];
- int n = is.read(buffer);
- while (n >= 0) {
- out.write(buffer, 0, n);
- n = is.read(buffer);
- }
- final byte[] bitmapBytes = out.toByteArray();
-
- // Determine the orientation for this image
- final int orientation = Exif.getOrientation(bitmapBytes);
- final Bitmap originalBitmap =
- BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, opts);
-
- if (originalBitmap != null && orientation != 0) {
- final Matrix matrix = new Matrix();
- matrix.postRotate(orientation);
- return Bitmap.createBitmap(originalBitmap, 0, 0, originalBitmap.getWidth(),
- originalBitmap.getHeight(), matrix, true);
- }
- return originalBitmap;
- } catch (OutOfMemoryError oome) {
- Log.e(TAG, "ImageUtils#decodeStream(InputStream, Rect, Options) threw an OOME", oome);
- return null;
- } catch (IOException ioe) {
- Log.e(TAG, "ImageUtils#decodeStream(InputStream, Rect, Options) threw an IOE", ioe);
- return null;
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // Do nothing
- }
- }
- }
- }
-
- /**
- * Gets the image bounds
- *
- * @param resolver The ContentResolver
- * @param uri The uri
- *
- * @return The image bounds
- */
- private static Point getImageBounds(ContentResolver resolver, Uri uri)
- throws IOException {
- final BitmapFactory.Options opts = new BitmapFactory.Options();
- InputStream inputStream = null;
-
- try {
- opts.inJustDecodeBounds = true;
- inputStream = resolver.openInputStream(uri);
- decodeStream(inputStream, null, opts);
-
- return new Point(opts.outWidth, opts.outHeight);
- } finally {
- try {
- if (inputStream != null) {
- inputStream.close();
- }
- } catch (IOException ignore) {
- }
- }
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/views/PhotoView.java b/photoviewer/src/com/android/ex/photo/views/PhotoView.java
deleted file mode 100644
index 8575bb1..0000000
--- a/photoviewer/src/com/android/ex/photo/views/PhotoView.java
+++ /dev/null
@@ -1,1288 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.views;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.BitmapDrawable;
-import android.support.v4.view.GestureDetectorCompat;
-import android.util.AttributeSet;
-import android.view.GestureDetector.OnGestureListener;
-import android.view.GestureDetector.OnDoubleTapListener;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.View;
-
-import com.android.ex.photo.R;
-import com.android.ex.photo.fragments.PhotoViewFragment.HorizontallyScrollable;
-
-/**
- * Layout for the photo list view header.
- */
-public class PhotoView extends View implements OnGestureListener,
- OnDoubleTapListener, ScaleGestureDetector.OnScaleGestureListener,
- HorizontallyScrollable {
- /** Zoom animation duration; in milliseconds */
- private final static long ZOOM_ANIMATION_DURATION = 300L;
- /** Rotate animation duration; in milliseconds */
- private final static long ROTATE_ANIMATION_DURATION = 500L;
- /** Snap animation duration; in milliseconds */
- private static final long SNAP_DURATION = 100L;
- /** Amount of time to wait before starting snap animation; in milliseconds */
- private static final long SNAP_DELAY = 250L;
- /** By how much to scale the image when double click occurs */
- private final static float DOUBLE_TAP_SCALE_FACTOR = 1.5f;
- /** Amount of translation needed before starting a snap animation */
- private final static float SNAP_THRESHOLD = 20.0f;
- /** The width & height of the bitmap returned by {@link #getCroppedPhoto()} */
- private final static float CROPPED_SIZE = 256.0f;
-
- /** If {@code true}, the static values have been initialized */
- private static boolean sInitialized;
-
- // Various dimensions
- /** Width & height of the crop region */
- private static int sCropSize;
-
- // Bitmaps
- /** Video icon */
- private static Bitmap sVideoImage;
- /** Video icon */
- private static Bitmap sVideoNotReadyImage;
-
- // Features
- private static boolean sHasMultitouchDistinct;
-
- // Paints
- /** Paint to partially dim the photo during crop */
- private static Paint sCropDimPaint;
- /** Paint to highlight the cropped portion of the photo */
- private static Paint sCropPaint;
-
- /** The photo to display */
- private BitmapDrawable mDrawable;
- /** The matrix used for drawing; this may be {@code null} */
- private Matrix mDrawMatrix;
- /** A matrix to apply the scaling of the photo */
- private Matrix mMatrix = new Matrix();
- /** The original matrix for this image; used to reset any transformations applied by the user */
- private Matrix mOriginalMatrix = new Matrix();
-
- /** The fixed height of this view. If {@code -1}, calculate the height */
- private int mFixedHeight = -1;
- /** When {@code true}, the view has been laid out */
- private boolean mHaveLayout;
- /** Whether or not the photo is full-screen */
- private boolean mFullScreen;
- /** Whether or not this is a still image of a video */
- private byte[] mVideoBlob;
- /** Whether or not this is a still image of a video */
- private boolean mVideoReady;
-
- /** Whether or not crop is allowed */
- private boolean mAllowCrop;
- /** The crop region */
- private Rect mCropRect = new Rect();
- /** Actual crop size; may differ from {@link #sCropSize} if the screen is smaller */
- private int mCropSize;
-
- /** Gesture detector */
- private GestureDetectorCompat mGestureDetector;
- /** Gesture detector that detects pinch gestures */
- private ScaleGestureDetector mScaleGetureDetector;
- /** An external click listener */
- private OnClickListener mExternalClickListener;
- /** When {@code true}, allows gestures to scale / pan the image */
- private boolean mTransformsEnabled;
-
- // To support zooming
- /** When {@code true}, a double tap scales the image by {@link #DOUBLE_TAP_SCALE_FACTOR} */
- private boolean mDoubleTapToZoomEnabled = true;
- /** When {@code true}, prevents scale end gesture from falsely triggering a double click. */
- private boolean mDoubleTapDebounce;
- /** When {@code false}, event is a scale gesture. Otherwise, event is a double touch. */
- private boolean mIsDoubleTouch;
- /** Runnable that scales the image */
- private ScaleRunnable mScaleRunnable;
- /** Minimum scale the image can have. */
- private float mMinScale;
- /** Maximum scale to limit scaling to, 0 means no limit. */
- private float mMaxScale;
-
- // To support translation [i.e. panning]
- /** Runnable that can move the image */
- private TranslateRunnable mTranslateRunnable;
- private SnapRunnable mSnapRunnable;
-
- // To support rotation
- /** The rotate runnable used to animate rotations of the image */
- private RotateRunnable mRotateRunnable;
- /** The current rotation amount, in degrees */
- private float mRotation;
-
- // Convenience fields
- // These are declared here not because they are important properties of the view. Rather, we
- // declare them here to avoid object allocation during critical graphics operations; such as
- // layout or drawing.
- /** Source (i.e. the photo size) bounds */
- private RectF mTempSrc = new RectF();
- /** Destination (i.e. the display) bounds. The image is scaled to this size. */
- private RectF mTempDst = new RectF();
- /** Rectangle to handle translations */
- private RectF mTranslateRect = new RectF();
- /** Array to store a copy of the matrix values */
- private float[] mValues = new float[9];
-
- public PhotoView(Context context) {
- super(context);
- initialize();
- }
-
- public PhotoView(Context context, AttributeSet attrs) {
- super(context, attrs);
- initialize();
- }
-
- public PhotoView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- initialize();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mScaleGetureDetector == null || mGestureDetector == null) {
- // We're being destroyed; ignore any touch events
- return true;
- }
-
- mScaleGetureDetector.onTouchEvent(event);
- mGestureDetector.onTouchEvent(event);
- final int action = event.getAction();
-
- switch (action) {
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- if (!mTranslateRunnable.mRunning) {
- snap();
- }
- break;
- }
-
- return true;
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- if (mDoubleTapToZoomEnabled && mTransformsEnabled) {
- if (!mDoubleTapDebounce) {
- float currentScale = getScale();
- float targetScale = currentScale * DOUBLE_TAP_SCALE_FACTOR;
-
- // Ensure the target scale is within our bounds
- targetScale = Math.max(mMinScale, targetScale);
- targetScale = Math.min(mMaxScale, targetScale);
-
- mScaleRunnable.start(currentScale, targetScale, e.getX(), e.getY());
- }
- mDoubleTapDebounce = false;
- }
- return true;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent e) {
- return true;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
- if (mExternalClickListener != null && !mIsDoubleTouch) {
- mExternalClickListener.onClick(this);
- }
- mIsDoubleTouch = false;
- return true;
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- if (mTransformsEnabled) {
- translate(-distanceX, -distanceY);
- }
- return true;
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- if (mTransformsEnabled) {
- mTranslateRunnable.stop();
- mSnapRunnable.stop();
- }
- return true;
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- if (mTransformsEnabled) {
- mTranslateRunnable.start(velocityX, velocityY);
- }
- return true;
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- if (mTransformsEnabled) {
- mIsDoubleTouch = false;
- float currentScale = getScale();
- float newScale = currentScale * detector.getScaleFactor();
- scale(newScale, detector.getFocusX(), detector.getFocusY());
- }
- return true;
- }
-
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- if (mTransformsEnabled) {
- mScaleRunnable.stop();
- mIsDoubleTouch = true;
- }
- return true;
- }
-
- @Override
- public void onScaleEnd(ScaleGestureDetector detector) {
- if (mTransformsEnabled && mIsDoubleTouch) {
- mDoubleTapDebounce = true;
- resetTransformations();
- }
- }
-
- @Override
- public void setOnClickListener(OnClickListener listener) {
- mExternalClickListener = listener;
- }
-
- @Override
- public boolean interceptMoveLeft(float origX, float origY) {
- if (!mTransformsEnabled) {
- // Allow intercept if we're not in transform mode
- return false;
- } else if (mTranslateRunnable.mRunning) {
- // Don't allow touch intercept until we've stopped flinging
- return true;
- } else {
- mMatrix.getValues(mValues);
- mTranslateRect.set(mTempSrc);
- mMatrix.mapRect(mTranslateRect);
-
- final float viewWidth = getWidth();
- final float transX = mValues[Matrix.MTRANS_X];
- final float drawWidth = mTranslateRect.right - mTranslateRect.left;
-
- if (!mTransformsEnabled || drawWidth <= viewWidth) {
- // Allow intercept if not in transform mode or the image is smaller than the view
- return false;
- } else if (transX == 0) {
- // We're at the left-side of the image; allow intercepting movements to the right
- return false;
- } else if (viewWidth >= drawWidth + transX) {
- // We're at the right-side of the image; allow intercepting movements to the left
- return true;
- } else {
- // We're in the middle of the image; don't allow touch intercept
- return true;
- }
- }
- }
-
- @Override
- public boolean interceptMoveRight(float origX, float origY) {
- if (!mTransformsEnabled) {
- // Allow intercept if we're not in transform mode
- return false;
- } else if (mTranslateRunnable.mRunning) {
- // Don't allow touch intercept until we've stopped flinging
- return true;
- } else {
- mMatrix.getValues(mValues);
- mTranslateRect.set(mTempSrc);
- mMatrix.mapRect(mTranslateRect);
-
- final float viewWidth = getWidth();
- final float transX = mValues[Matrix.MTRANS_X];
- final float drawWidth = mTranslateRect.right - mTranslateRect.left;
-
- if (!mTransformsEnabled || drawWidth <= viewWidth) {
- // Allow intercept if not in transform mode or the image is smaller than the view
- return false;
- } else if (transX == 0) {
- // We're at the left-side of the image; allow intercepting movements to the right
- return true;
- } else if (viewWidth >= drawWidth + transX) {
- // We're at the right-side of the image; allow intercepting movements to the left
- return false;
- } else {
- // We're in the middle of the image; don't allow touch intercept
- return true;
- }
- }
- }
-
- /**
- * Free all resources held by this view.
- * The view is on its way to be collected and will not be reused.
- */
- public void clear() {
- mGestureDetector = null;
- mScaleGetureDetector = null;
- mDrawable = null;
- mScaleRunnable.stop();
- mScaleRunnable = null;
- mTranslateRunnable.stop();
- mTranslateRunnable = null;
- mSnapRunnable.stop();
- mSnapRunnable = null;
- mRotateRunnable.stop();
- mRotateRunnable = null;
- setOnClickListener(null);
- mExternalClickListener = null;
- }
-
- /**
- * Binds a bitmap to the view.
- *
- * @param photoBitmap the bitmap to bind.
- */
- public void bindPhoto(Bitmap photoBitmap) {
- boolean changed = false;
- if (mDrawable != null) {
- final Bitmap drawableBitmap = mDrawable.getBitmap();
- if (photoBitmap == drawableBitmap) {
- // setting the same bitmap; do nothing
- return;
- }
-
- changed = photoBitmap != null &&
- (mDrawable.getIntrinsicWidth() != photoBitmap.getWidth() ||
- mDrawable.getIntrinsicHeight() != photoBitmap.getHeight());
-
- // Reset mMinScale to ensure the bounds / matrix are recalculated
- mMinScale = 0f;
- mDrawable = null;
- }
-
- if (mDrawable == null && photoBitmap != null) {
- mDrawable = new BitmapDrawable(getResources(), photoBitmap);
- }
-
- configureBounds(changed);
- invalidate();
- }
-
- /**
- * Returns the bound photo data if set. Otherwise, {@code null}.
- */
- public Bitmap getPhoto() {
- if (mDrawable != null) {
- return mDrawable.getBitmap();
- }
- return null;
- }
-
- /**
- * Gets video data associated with this item. Returns {@code null} if this is not a video.
- */
- public byte[] getVideoData() {
- return mVideoBlob;
- }
-
- /**
- * Returns {@code true} if the photo represents a video. Otherwise, {@code false}.
- */
- public boolean isVideo() {
- return mVideoBlob != null;
- }
-
- /**
- * Returns {@code true} if the video is ready to play. Otherwise, {@code false}.
- */
- public boolean isVideoReady() {
- return mVideoBlob != null && mVideoReady;
- }
-
- /**
- * Returns {@code true} if a photo has been bound. Otherwise, {@code false}.
- */
- public boolean isPhotoBound() {
- return mDrawable != null;
- }
-
- /**
- * Hides the photo info portion of the header. As a side effect, this automatically enables
- * or disables image transformations [eg zoom, pan, etc...] depending upon the value of
- * fullScreen. If this is not desirable, enable / disable image transformations manually.
- */
- public void setFullScreen(boolean fullScreen, boolean animate) {
- if (fullScreen != mFullScreen) {
- mFullScreen = fullScreen;
- requestLayout();
- invalidate();
- }
- }
-
- /**
- * Enable or disable cropping of the displayed image. Cropping can only be enabled
- * <em>before</em> the view has been laid out. Additionally, once cropping has been
- * enabled, it cannot be disabled.
- */
- public void enableAllowCrop(boolean allowCrop) {
- if (allowCrop && mHaveLayout) {
- throw new IllegalArgumentException("Cannot set crop after view has been laid out");
- }
- if (!allowCrop && mAllowCrop) {
- throw new IllegalArgumentException("Cannot unset crop mode");
- }
- mAllowCrop = allowCrop;
- }
-
- /**
- * Gets a bitmap of the cropped region. If cropping is not enabled, returns {@code null}.
- */
- public Bitmap getCroppedPhoto() {
- if (!mAllowCrop) {
- return null;
- }
-
- final Bitmap croppedBitmap = Bitmap.createBitmap(
- (int) CROPPED_SIZE, (int) CROPPED_SIZE, Bitmap.Config.ARGB_8888);
- final Canvas croppedCanvas = new Canvas(croppedBitmap);
-
- // scale for the final dimensions
- final int cropWidth = mCropRect.right - mCropRect.left;
- final float scaleWidth = CROPPED_SIZE / cropWidth;
- final float scaleHeight = CROPPED_SIZE / cropWidth;
-
- // translate to the origin & scale
- final Matrix matrix = new Matrix(mDrawMatrix);
- matrix.postTranslate(-mCropRect.left, -mCropRect.top);
- matrix.postScale(scaleWidth, scaleHeight);
-
- // draw the photo
- if (mDrawable != null) {
- croppedCanvas.concat(matrix);
- mDrawable.draw(croppedCanvas);
- }
- return croppedBitmap;
- }
-
- /**
- * Resets the image transformation to its original value.
- */
- public void resetTransformations() {
- // snap transformations; we don't animate
- mMatrix.set(mOriginalMatrix);
-
- // Invalidate the view because if you move off this PhotoView
- // to another one and come back, you want it to draw from scratch
- // in case you were zoomed in or translated (since those settings
- // are not preserved and probably shouldn't be).
- invalidate();
- }
-
- /**
- * Rotates the image 90 degrees, clockwise.
- */
- public void rotateClockwise() {
- rotate(90, true);
- }
-
- /**
- * Rotates the image 90 degrees, counter clockwise.
- */
- public void rotateCounterClockwise() {
- rotate(-90, true);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- // draw the photo
- if (mDrawable != null) {
- int saveCount = canvas.getSaveCount();
- canvas.save();
-
- if (mDrawMatrix != null) {
- canvas.concat(mDrawMatrix);
- }
- mDrawable.draw(canvas);
-
- canvas.restoreToCount(saveCount);
-
- if (mVideoBlob != null) {
- final Bitmap videoImage = (mVideoReady ? sVideoImage : sVideoNotReadyImage);
- final int drawLeft = (getWidth() - videoImage.getWidth()) / 2;
- final int drawTop = (getHeight() - videoImage.getHeight()) / 2;
- canvas.drawBitmap(videoImage, drawLeft, drawTop, null);
- }
-
- // Extract the drawable's bounds (in our own copy, to not alter the image)
- mTranslateRect.set(mDrawable.getBounds());
- if (mDrawMatrix != null) {
- mDrawMatrix.mapRect(mTranslateRect);
- }
-
- if (mAllowCrop) {
- int previousSaveCount = canvas.getSaveCount();
- canvas.drawRect(0, 0, getWidth(), getHeight(), sCropDimPaint);
- canvas.save();
- canvas.clipRect(mCropRect);
-
- if (mDrawMatrix != null) {
- canvas.concat(mDrawMatrix);
- }
-
- mDrawable.draw(canvas);
- canvas.restoreToCount(previousSaveCount);
- canvas.drawRect(mCropRect, sCropPaint);
- }
- }
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mHaveLayout = true;
- final int layoutWidth = getWidth();
- final int layoutHeight = getHeight();
-
- if (mAllowCrop) {
- mCropSize = Math.min(sCropSize, Math.min(layoutWidth, layoutHeight));
- final int cropLeft = (layoutWidth - mCropSize) / 2;
- final int cropTop = (layoutHeight - mCropSize) / 2;
- final int cropRight = cropLeft + mCropSize;
- final int cropBottom = cropTop + mCropSize;
-
- // Create a crop region overlay. We need a separate canvas to be able to "punch
- // a hole" through to the underlying image.
- mCropRect.set(cropLeft, cropTop, cropRight, cropBottom);
- }
- configureBounds(changed);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (mFixedHeight != -1) {
- super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(mFixedHeight,
- MeasureSpec.AT_MOST));
- setMeasuredDimension(getMeasuredWidth(), mFixedHeight);
- } else {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
- }
-
- /**
- * Forces a fixed height for this view.
- *
- * @param fixedHeight The height. If {@code -1}, use the measured height.
- */
- public void setFixedHeight(int fixedHeight) {
- final boolean adjustBounds = (fixedHeight != mFixedHeight);
- mFixedHeight = fixedHeight;
- setMeasuredDimension(getMeasuredWidth(), mFixedHeight);
- if (adjustBounds) {
- configureBounds(true);
- requestLayout();
- }
- }
-
- /**
- * Enable or disable image transformations. When transformations are enabled, this view
- * consumes all touch events.
- */
- public void enableImageTransforms(boolean enable) {
- mTransformsEnabled = enable;
- if (!mTransformsEnabled) {
- resetTransformations();
- }
- }
-
- /**
- * Configures the bounds of the photo. The photo will always be scaled to fit center.
- */
- private void configureBounds(boolean changed) {
- if (mDrawable == null || !mHaveLayout) {
- return;
- }
- final int dwidth = mDrawable.getIntrinsicWidth();
- final int dheight = mDrawable.getIntrinsicHeight();
-
- final int vwidth = getWidth();
- final int vheight = getHeight();
-
- final boolean fits = (dwidth < 0 || vwidth == dwidth) &&
- (dheight < 0 || vheight == dheight);
-
- // We need to do the scaling ourself, so have the drawable use its native size.
- mDrawable.setBounds(0, 0, dwidth, dheight);
-
- // Create a matrix with the proper transforms
- if (changed || (mMinScale == 0 && mDrawable != null && mHaveLayout)) {
- generateMatrix();
- generateScale();
- }
-
- if (fits || mMatrix.isIdentity()) {
- // The bitmap fits exactly, no transform needed.
- mDrawMatrix = null;
- } else {
- mDrawMatrix = mMatrix;
- }
- }
-
- /**
- * Generates the initial transformation matrix for drawing. Additionally, it sets the
- * minimum and maximum scale values.
- */
- private void generateMatrix() {
- final int dwidth = mDrawable.getIntrinsicWidth();
- final int dheight = mDrawable.getIntrinsicHeight();
-
- final int vwidth = mAllowCrop ? sCropSize : getWidth();
- final int vheight = mAllowCrop ? sCropSize : getHeight();
-
- final boolean fits = (dwidth < 0 || vwidth == dwidth) &&
- (dheight < 0 || vheight == dheight);
-
- if (fits && !mAllowCrop) {
- mMatrix.reset();
- } else {
- // Generate the required transforms for the photo
- mTempSrc.set(0, 0, dwidth, dheight);
- if (mAllowCrop) {
- mTempDst.set(mCropRect);
- } else {
- mTempDst.set(0, 0, vwidth, vheight);
- }
-
- if (dwidth < vwidth && dheight < vheight && !mAllowCrop) {
- mMatrix.setTranslate(vwidth / 2 - dwidth / 2, vheight / 2 - dheight / 2);
- } else {
- mMatrix.setRectToRect(mTempSrc, mTempDst, Matrix.ScaleToFit.CENTER);
- }
- }
- mOriginalMatrix.set(mMatrix);
- }
-
- private void generateScale() {
- final int dwidth = mDrawable.getIntrinsicWidth();
- final int dheight = mDrawable.getIntrinsicHeight();
-
- final int vwidth = mAllowCrop ? getCropSize() : getWidth();
- final int vheight = mAllowCrop ? getCropSize() : getHeight();
-
- if (dwidth < vwidth && dheight < vheight && !mAllowCrop) {
- mMinScale = 1.0f;
- } else {
- mMinScale = getScale();
- }
- mMaxScale = Math.max(mMinScale * 8, 8);
- }
-
- /**
- * @return the size of the crop regions
- */
- private int getCropSize() {
- return mCropSize > 0 ? mCropSize : sCropSize;
- }
-
- /**
- * Returns the currently applied scale factor for the image.
- * <p>
- * NOTE: This method overwrites any values stored in {@link #mValues}.
- */
- private float getScale() {
- mMatrix.getValues(mValues);
- return mValues[Matrix.MSCALE_X];
- }
-
- /**
- * Scales the image while keeping the aspect ratio.
- *
- * The given scale is capped so that the resulting scale of the image always remains
- * between {@link #mMinScale} and {@link #mMaxScale}.
- *
- * The scaled image is never allowed to be outside of the viewable area. If the image
- * is smaller than the viewable area, it will be centered.
- *
- * @param newScale the new scale
- * @param centerX the center horizontal point around which to scale
- * @param centerY the center vertical point around which to scale
- */
- private void scale(float newScale, float centerX, float centerY) {
- // rotate back to the original orientation
- mMatrix.postRotate(-mRotation, getWidth() / 2, getHeight() / 2);
-
- // ensure that mMixScale <= newScale <= mMaxScale
- newScale = Math.max(newScale, mMinScale);
- newScale = Math.min(newScale, mMaxScale);
-
- float currentScale = getScale();
- float factor = newScale / currentScale;
-
- // apply the scale factor
- mMatrix.postScale(factor, factor, centerX, centerY);
-
- // ensure the image is within the view bounds
- snap();
-
- // re-apply any rotation
- mMatrix.postRotate(mRotation, getWidth() / 2, getHeight() / 2);
-
- invalidate();
- }
-
- /**
- * Translates the image.
- *
- * This method will not allow the image to be translated outside of the visible area.
- *
- * @param tx how many pixels to translate horizontally
- * @param ty how many pixels to translate vertically
- * @return {@code true} if the translation was applied as specified. Otherwise, {@code false}
- * if the translation was modified.
- */
- private boolean translate(float tx, float ty) {
- mTranslateRect.set(mTempSrc);
- mMatrix.mapRect(mTranslateRect);
-
- final float maxLeft = mAllowCrop ? mCropRect.left : 0.0f;
- final float maxRight = mAllowCrop ? mCropRect.right : getWidth();
- float l = mTranslateRect.left;
- float r = mTranslateRect.right;
-
- final float translateX;
- if (mAllowCrop) {
- // If we're cropping, allow the image to scroll off the edge of the screen
- translateX = Math.max(maxLeft - mTranslateRect.right,
- Math.min(maxRight - mTranslateRect.left, tx));
- } else {
- // Otherwise, ensure the image never leaves the screen
- if (r - l < maxRight - maxLeft) {
- translateX = maxLeft + ((maxRight - maxLeft) - (r + l)) / 2;
- } else {
- translateX = Math.max(maxRight - r, Math.min(maxLeft - l, tx));
- }
- }
-
- float maxTop = mAllowCrop ? mCropRect.top: 0.0f;
- float maxBottom = mAllowCrop ? mCropRect.bottom : getHeight();
- float t = mTranslateRect.top;
- float b = mTranslateRect.bottom;
-
- final float translateY;
-
- if (mAllowCrop) {
- // If we're cropping, allow the image to scroll off the edge of the screen
- translateY = Math.max(maxTop - mTranslateRect.bottom,
- Math.min(maxBottom - mTranslateRect.top, ty));
- } else {
- // Otherwise, ensure the image never leaves the screen
- if (b - t < maxBottom - maxTop) {
- translateY = maxTop + ((maxBottom - maxTop) - (b + t)) / 2;
- } else {
- translateY = Math.max(maxBottom - b, Math.min(maxTop - t, ty));
- }
- }
-
- // Do the translation
- mMatrix.postTranslate(translateX, translateY);
- invalidate();
-
- return (translateX == tx) && (translateY == ty);
- }
-
- /**
- * Snaps the image so it touches all edges of the view.
- */
- private void snap() {
- mTranslateRect.set(mTempSrc);
- mMatrix.mapRect(mTranslateRect);
-
- // Determine how much to snap in the horizontal direction [if any]
- float maxLeft = mAllowCrop ? mCropRect.left : 0.0f;
- float maxRight = mAllowCrop ? mCropRect.right : getWidth();
- float l = mTranslateRect.left;
- float r = mTranslateRect.right;
-
- final float translateX;
- if (r - l < maxRight - maxLeft) {
- // Image is narrower than view; translate to the center of the view
- translateX = maxLeft + ((maxRight - maxLeft) - (r + l)) / 2;
- } else if (l > maxLeft) {
- // Image is off right-edge of screen; bring it into view
- translateX = maxLeft - l;
- } else if (r < maxRight) {
- // Image is off left-edge of screen; bring it into view
- translateX = maxRight - r;
- } else {
- translateX = 0.0f;
- }
-
- // Determine how much to snap in the vertical direction [if any]
- float maxTop = mAllowCrop ? mCropRect.top : 0.0f;
- float maxBottom = mAllowCrop ? mCropRect.bottom : getHeight();
- float t = mTranslateRect.top;
- float b = mTranslateRect.bottom;
-
- final float translateY;
- if (b - t < maxBottom - maxTop) {
- // Image is shorter than view; translate to the bottom edge of the view
- translateY = maxTop + ((maxBottom - maxTop) - (b + t)) / 2;
- } else if (t > maxTop) {
- // Image is off bottom-edge of screen; bring it into view
- translateY = maxTop - t;
- } else if (b < maxBottom) {
- // Image is off top-edge of screen; bring it into view
- translateY = maxBottom - b;
- } else {
- translateY = 0.0f;
- }
-
- if (Math.abs(translateX) > SNAP_THRESHOLD || Math.abs(translateY) > SNAP_THRESHOLD) {
- mSnapRunnable.start(translateX, translateY);
- } else {
- mMatrix.postTranslate(translateX, translateY);
- invalidate();
- }
- }
-
- /**
- * Rotates the image, either instantly or gradually
- *
- * @param degrees how many degrees to rotate the image, positive rotates clockwise
- * @param animate if {@code true}, animate during the rotation. Otherwise, snap rotate.
- */
- private void rotate(float degrees, boolean animate) {
- if (animate) {
- mRotateRunnable.start(degrees);
- } else {
- mRotation += degrees;
- mMatrix.postRotate(degrees, getWidth() / 2, getHeight() / 2);
- invalidate();
- }
- }
-
- /**
- * Initializes the header and any static values
- */
- private void initialize() {
- Context context = getContext();
-
- if (!sInitialized) {
- sInitialized = true;
-
- Resources resources = context.getApplicationContext().getResources();
-
- sCropSize = resources.getDimensionPixelSize(R.dimen.photo_crop_width);
-
- sCropDimPaint = new Paint();
- sCropDimPaint.setAntiAlias(true);
- sCropDimPaint.setColor(resources.getColor(R.color.photo_crop_dim_color));
- sCropDimPaint.setStyle(Style.FILL);
-
- sCropPaint = new Paint();
- sCropPaint.setAntiAlias(true);
- sCropPaint.setColor(resources.getColor(R.color.photo_crop_highlight_color));
- sCropPaint.setStyle(Style.STROKE);
- sCropPaint.setStrokeWidth(resources.getDimension(R.dimen.photo_crop_stroke_width));
- }
-
- mGestureDetector = new GestureDetectorCompat(context, this, null);
- mScaleGetureDetector = new ScaleGestureDetector(context, this);
- mScaleRunnable = new ScaleRunnable(this);
- mTranslateRunnable = new TranslateRunnable(this);
- mSnapRunnable = new SnapRunnable(this);
- mRotateRunnable = new RotateRunnable(this);
- }
-
- /**
- * Runnable that animates an image scale operation.
- */
- private static class ScaleRunnable implements Runnable {
-
- private final PhotoView mHeader;
-
- private float mCenterX;
- private float mCenterY;
-
- private boolean mZoomingIn;
-
- private float mTargetScale;
- private float mStartScale;
- private float mVelocity;
- private long mStartTime;
-
- private boolean mRunning;
- private boolean mStop;
-
- public ScaleRunnable(PhotoView header) {
- mHeader = header;
- }
-
- /**
- * Starts the animation. There is no target scale bounds check.
- */
- public boolean start(float startScale, float targetScale, float centerX, float centerY) {
- if (mRunning) {
- return false;
- }
-
- mCenterX = centerX;
- mCenterY = centerY;
-
- // Ensure the target scale is within the min/max bounds
- mTargetScale = targetScale;
- mStartTime = System.currentTimeMillis();
- mStartScale = startScale;
- mZoomingIn = mTargetScale > mStartScale;
- mVelocity = (mTargetScale - mStartScale) / ZOOM_ANIMATION_DURATION;
- mRunning = true;
- mStop = false;
- mHeader.post(this);
- return true;
- }
-
- /**
- * Stops the animation in place. It does not snap the image to its final zoom.
- */
- public void stop() {
- mRunning = false;
- mStop = true;
- }
-
- @Override
- public void run() {
- if (mStop) {
- return;
- }
-
- // Scale
- long now = System.currentTimeMillis();
- long ellapsed = now - mStartTime;
- float newScale = (mStartScale + mVelocity * ellapsed);
- mHeader.scale(newScale, mCenterX, mCenterY);
-
- // Stop when done
- if (newScale == mTargetScale || (mZoomingIn == (newScale > mTargetScale))) {
- mHeader.scale(mTargetScale, mCenterX, mCenterY);
- stop();
- }
-
- if (!mStop) {
- mHeader.post(this);
- }
- }
- }
-
- /**
- * Runnable that animates an image translation operation.
- */
- private static class TranslateRunnable implements Runnable {
-
- private static final float DECELERATION_RATE = 1000f;
- private static final long NEVER = -1L;
-
- private final PhotoView mHeader;
-
- private float mVelocityX;
- private float mVelocityY;
-
- private long mLastRunTime;
- private boolean mRunning;
- private boolean mStop;
-
- public TranslateRunnable(PhotoView header) {
- mLastRunTime = NEVER;
- mHeader = header;
- }
-
- /**
- * Starts the animation.
- */
- public boolean start(float velocityX, float velocityY) {
- if (mRunning) {
- return false;
- }
- mLastRunTime = NEVER;
- mVelocityX = velocityX;
- mVelocityY = velocityY;
- mStop = false;
- mRunning = true;
- mHeader.post(this);
- return true;
- }
-
- /**
- * Stops the animation in place. It does not snap the image to its final translation.
- */
- public void stop() {
- mRunning = false;
- mStop = true;
- }
-
- @Override
- public void run() {
- // See if we were told to stop:
- if (mStop) {
- return;
- }
-
- // Translate according to current velocities and time delta:
- long now = System.currentTimeMillis();
- float delta = (mLastRunTime != NEVER) ? (now - mLastRunTime) / 1000f : 0f;
- final boolean didTranslate = mHeader.translate(mVelocityX * delta, mVelocityY * delta);
- mLastRunTime = now;
- // Slow down:
- float slowDown = DECELERATION_RATE * delta;
- if (mVelocityX > 0f) {
- mVelocityX -= slowDown;
- if (mVelocityX < 0f) {
- mVelocityX = 0f;
- }
- } else {
- mVelocityX += slowDown;
- if (mVelocityX > 0f) {
- mVelocityX = 0f;
- }
- }
- if (mVelocityY > 0f) {
- mVelocityY -= slowDown;
- if (mVelocityY < 0f) {
- mVelocityY = 0f;
- }
- } else {
- mVelocityY += slowDown;
- if (mVelocityY > 0f) {
- mVelocityY = 0f;
- }
- }
-
- // Stop when done
- if ((mVelocityX == 0f && mVelocityY == 0f) || !didTranslate) {
- stop();
- mHeader.snap();
- }
-
- // See if we need to continue flinging:
- if (mStop) {
- return;
- }
- mHeader.post(this);
- }
- }
-
- /**
- * Runnable that animates an image translation operation.
- */
- private static class SnapRunnable implements Runnable {
-
- private static final long NEVER = -1L;
-
- private final PhotoView mHeader;
-
- private float mTranslateX;
- private float mTranslateY;
-
- private long mStartRunTime;
- private boolean mRunning;
- private boolean mStop;
-
- public SnapRunnable(PhotoView header) {
- mStartRunTime = NEVER;
- mHeader = header;
- }
-
- /**
- * Starts the animation.
- */
- public boolean start(float translateX, float translateY) {
- if (mRunning) {
- return false;
- }
- mStartRunTime = NEVER;
- mTranslateX = translateX;
- mTranslateY = translateY;
- mStop = false;
- mRunning = true;
- mHeader.postDelayed(this, SNAP_DELAY);
- return true;
- }
-
- /**
- * Stops the animation in place. It does not snap the image to its final translation.
- */
- public void stop() {
- mRunning = false;
- mStop = true;
- }
-
- @Override
- public void run() {
- // See if we were told to stop:
- if (mStop) {
- return;
- }
-
- // Translate according to current velocities and time delta:
- long now = System.currentTimeMillis();
- float delta = (mStartRunTime != NEVER) ? (now - mStartRunTime) : 0f;
-
- if (mStartRunTime == NEVER) {
- mStartRunTime = now;
- }
-
- float transX;
- float transY;
- if (delta >= SNAP_DURATION) {
- transX = mTranslateX;
- transY = mTranslateY;
- } else {
- transX = (mTranslateX / (SNAP_DURATION - delta)) * 10f;
- transY = (mTranslateY / (SNAP_DURATION - delta)) * 10f;
- if (Math.abs(transX) > Math.abs(mTranslateX) || transX == Float.NaN) {
- transX = mTranslateX;
- }
- if (Math.abs(transY) > Math.abs(mTranslateY) || transY == Float.NaN) {
- transY = mTranslateY;
- }
- }
-
- mHeader.translate(transX, transY);
- mTranslateX -= transX;
- mTranslateY -= transY;
-
- if (mTranslateX == 0 && mTranslateY == 0) {
- stop();
- }
-
- // See if we need to continue flinging:
- if (mStop) {
- return;
- }
- mHeader.post(this);
- }
- }
-
- /**
- * Runnable that animates an image rotation operation.
- */
- private static class RotateRunnable implements Runnable {
-
- private static final long NEVER = -1L;
-
- private final PhotoView mHeader;
-
- private float mTargetRotation;
- private float mAppliedRotation;
- private float mVelocity;
- private long mLastRuntime;
-
- private boolean mRunning;
- private boolean mStop;
-
- public RotateRunnable(PhotoView header) {
- mHeader = header;
- }
-
- /**
- * Starts the animation.
- */
- public void start(float rotation) {
- if (mRunning) {
- return;
- }
-
- mTargetRotation = rotation;
- mVelocity = mTargetRotation / ROTATE_ANIMATION_DURATION;
- mAppliedRotation = 0f;
- mLastRuntime = NEVER;
- mStop = false;
- mRunning = true;
- mHeader.post(this);
- }
-
- /**
- * Stops the animation in place. It does not snap the image to its final rotation.
- */
- public void stop() {
- mRunning = false;
- mStop = true;
- }
-
- @Override
- public void run() {
- if (mStop) {
- return;
- }
-
- if (mAppliedRotation != mTargetRotation) {
- long now = System.currentTimeMillis();
- long delta = mLastRuntime != NEVER ? now - mLastRuntime : 0L;
- float rotationAmount = mVelocity * delta;
- if (mAppliedRotation < mTargetRotation
- && mAppliedRotation + rotationAmount > mTargetRotation
- || mAppliedRotation > mTargetRotation
- && mAppliedRotation + rotationAmount < mTargetRotation) {
- rotationAmount = mTargetRotation - mAppliedRotation;
- }
- mHeader.rotate(rotationAmount, false);
- mAppliedRotation += rotationAmount;
- if (mAppliedRotation == mTargetRotation) {
- stop();
- }
- mLastRuntime = now;
- }
-
- if (mStop) {
- return;
- }
- mHeader.post(this);
- }
- }
-}
diff --git a/photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java b/photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java
deleted file mode 100644
index 2669273..0000000
--- a/photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc.
- * Licensed to The Android Open Source Project.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ex.photo.views;
-
-import android.view.View;
-import android.widget.ProgressBar;
-
-/**
- * This class wraps around two progress bars and is solely designed to fix
- * a bug in the framework (b/6928449) that prevents a progress bar from
- * gracefully switching back and forth between indeterminate and determinate
- * modes.
- */
-public class ProgressBarWrapper {
- private final ProgressBar mDeterminate;
- private final ProgressBar mIndeterminate;
- private boolean mIsIndeterminate;
-
- public ProgressBarWrapper(ProgressBar determinate,
- ProgressBar indeterminate, boolean isIndeterminate) {
- mDeterminate = determinate;
- mIndeterminate = indeterminate;
- setIndeterminate(isIndeterminate);
- }
-
- public void setIndeterminate(boolean isIndeterminate) {
- mIsIndeterminate = isIndeterminate;
-
- setVisibility(mIsIndeterminate);
- }
-
- public void setVisibility(int visibility) {
- if (visibility == View.INVISIBLE || visibility == View.GONE) {
- mIndeterminate.setVisibility(visibility);
- mDeterminate.setVisibility(visibility);
- } else {
- setVisibility(mIsIndeterminate);
- }
- }
-
- private void setVisibility(boolean isIndeterminate) {
- mIndeterminate.setVisibility(isIndeterminate ? View.VISIBLE : View.GONE);
- mDeterminate.setVisibility(isIndeterminate ? View.GONE : View.VISIBLE);
- }
-
- public void setMax(int max) {
- mDeterminate.setMax(max);
- }
-
- public void setProgress(int progress) {
- mDeterminate.setProgress(progress);
- }
-}
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 \