diff options
Diffstat (limited to 'src')
8 files changed, 350 insertions, 45 deletions
diff --git a/src/com/android/dreams/phototable/AlbumDataAdapter.java b/src/com/android/dreams/phototable/AlbumDataAdapter.java index 3d68627..099fd90 100644 --- a/src/com/android/dreams/phototable/AlbumDataAdapter.java +++ b/src/com/android/dreams/phototable/AlbumDataAdapter.java @@ -15,8 +15,9 @@ */ package com.android.dreams.phototable; -import android.content.SharedPreferences; import android.content.Context; +import android.content.SharedPreferences; +import android.text.SpannableString; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -24,7 +25,6 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CheckBox; -import android.widget.CompoundButton; import android.widget.TextView; import java.util.Comparator; @@ -37,6 +37,7 @@ import java.util.Set; */ public class AlbumDataAdapter extends ArrayAdapter<PhotoSource.AlbumData> { private static final String TAG = "AlbumDataAdapter"; + private static final boolean DEBUG = false; public static final String ALBUM_SET = "Enabled Album Set"; @@ -58,60 +59,116 @@ public class AlbumDataAdapter extends ArrayAdapter<PhotoSource.AlbumData> { } @Override - public View getView (int position, View convertView, ViewGroup parent) { + public View getView(int position, View convertView, ViewGroup parent) { View item = convertView; if (item == null) { item = mInflater.inflate(mLayout, parent, false); - } else { } PhotoSource.AlbumData data = getItem(position); View vCheckBox = item.findViewById(R.id.enabled); if (vCheckBox != null && vCheckBox instanceof CheckBox) { CheckBox checkBox = (CheckBox) vCheckBox; - checkBox.setOnCheckedChangeListener(null); checkBox.setChecked(mEnabledAlbums.contains(data.id)); - checkBox.setText(data.toString()); checkBox.setTag(R.id.data_payload, data); - checkBox.setOnCheckedChangeListener(mListener); } + View vTextView = item.findViewById(R.id.title); + if (vTextView != null && vTextView instanceof TextView) { + TextView textView = (TextView) vTextView; + textView.setText(data.title); + } + + item.setOnClickListener(mListener); return item; } + public static class AccountComparator implements Comparator<PhotoSource.AlbumData> { + private final RecencyComparator recency; + public AccountComparator() { + recency = new RecencyComparator(); + } + + @Override + public int compare(PhotoSource.AlbumData a, PhotoSource.AlbumData b) { + if (a.account == b.account) { + return recency.compare(a, b); + } else { + String typeAString = a.getType(); + String typeBString = b.getType(); + int typeA = 1; + int typeB = 1; + + if (typeAString.equals(LocalSource.class.getName())) { + typeA = 0; + } + if (typeBString.equals(LocalSource.class.getName())) { + typeB = 0; + } + + if (typeAString.equals(StockSource.class.getName())) { + typeA = 2; + } + if (typeBString.equals(StockSource.class.getName())) { + typeB = 2; + } + + if (typeA == typeB) { + return a.account.compareTo(b.account); + } else { + return (int) Math.signum(typeA - typeB); + } + } + } + } + public static class RecencyComparator implements Comparator<PhotoSource.AlbumData> { + private final TitleComparator title; + public RecencyComparator() { + title = new TitleComparator(); + } + @Override public int compare(PhotoSource.AlbumData a, PhotoSource.AlbumData b) { if (a.updated == b.updated) { - return a.title.compareTo(b.title); + return title.compare(a, b); } else { return (int) Math.signum(b.updated - a.updated); } } } - public static class AlphabeticalComparator implements Comparator<PhotoSource.AlbumData> { + public static class TitleComparator implements Comparator<PhotoSource.AlbumData> { @Override public int compare(PhotoSource.AlbumData a, PhotoSource.AlbumData b) { return a.title.compareTo(b.title); } } - private class ItemClickListener implements CompoundButton.OnCheckedChangeListener { + private class ItemClickListener implements OnClickListener { @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - PhotoSource.AlbumData data = - (PhotoSource.AlbumData) buttonView.getTag(R.id.data_payload); - - if (isChecked) { - mEnabledAlbums.add(data.id); + public void onClick(View v) { + final View vCheckBox = v.findViewById(R.id.enabled); + if (vCheckBox != null && vCheckBox instanceof CheckBox) { + final CheckBox checkBox = (CheckBox) vCheckBox; + final PhotoSource.AlbumData data = + (PhotoSource.AlbumData) checkBox.getTag(R.id.data_payload); + final boolean isChecked = !checkBox.isChecked(); + checkBox.setChecked(isChecked); + + if (isChecked) { + mEnabledAlbums.add(data.id); + } else { + mEnabledAlbums.remove(data.id); + } + + AlbumSettings.setEnabledAlbums(mSettings , mEnabledAlbums); + if (DEBUG) Log.i(TAG, data.title + " is " + + (isChecked ? "" : "not") + " enabled"); } else { - mEnabledAlbums.remove(data.id); + if (DEBUG) Log.w(TAG, "no checkbox found in settings row!"); } - - AlbumSettings.setEnabledAlbums(mSettings , mEnabledAlbums); - - Log.i("adaptor", data.title + " is " + (isChecked ? "" : "not") + " enabled"); + v.setPressed(true); } } } diff --git a/src/com/android/dreams/phototable/FlipperDreamSettings.java b/src/com/android/dreams/phototable/FlipperDreamSettings.java index 0ae20df..720599f 100644 --- a/src/com/android/dreams/phototable/FlipperDreamSettings.java +++ b/src/com/android/dreams/phototable/FlipperDreamSettings.java @@ -18,7 +18,7 @@ package com.android.dreams.phototable; import android.content.SharedPreferences; import android.app.ListActivity; import android.os.Bundle; -import android.widget.ArrayAdapter; +import android.widget.ListAdapter; import java.util.LinkedList; @@ -30,7 +30,7 @@ public class FlipperDreamSettings extends ListActivity { public static final String PREFS_NAME = FlipperDream.TAG; private PhotoSourcePlexor mPhotoSource; - private ArrayAdapter<PhotoSource.AlbumData> mAdapter; + private ListAdapter mAdapter; private SharedPreferences mSettings; @Override @@ -42,11 +42,11 @@ public class FlipperDreamSettings extends ListActivity { mSettings = getSharedPreferences(PREFS_NAME, 0); mPhotoSource = new PhotoSourcePlexor(this, mSettings); - mAdapter = new AlbumDataAdapter(this, + mAdapter = new SectionedAlbumDataAdapter(this, mSettings, + R.layout.header, R.layout.album, new LinkedList<PhotoSource.AlbumData>(mPhotoSource.findAlbums())); - mAdapter.sort(new AlbumDataAdapter.RecencyComparator()); setListAdapter(mAdapter); } } diff --git a/src/com/android/dreams/phototable/LocalSource.java b/src/com/android/dreams/phototable/LocalSource.java index ec23b6a..e453378 100644 --- a/src/com/android/dreams/phototable/LocalSource.java +++ b/src/com/android/dreams/phototable/LocalSource.java @@ -32,10 +32,14 @@ import java.util.LinkedList; public class LocalSource extends PhotoSource { private static final String TAG = "PhotoTable.LocalSource"; + private final String mUnknownAlbumName; + private final String mLocalSourceName; private int mNextPosition; public LocalSource(Context context, SharedPreferences settings) { super(context, settings); + mLocalSourceName = mResources.getString(R.string.local_source_name, "Photos on Device"); + mUnknownAlbumName = mResources.getString(R.string.unknown_album_name, "Unknown"); mSourceName = TAG; mNextPosition = -1; fillQueue(); @@ -68,6 +72,7 @@ public class LocalSource extends PhotoSource { if (foundAlbums.get(id) == null) { data = new AlbumData(); data.id = id; + data.account = mLocalSourceName; if (dataIndex >= 0) { data.thumbnailUrl = cursor.getString(dataIndex); @@ -76,8 +81,7 @@ public class LocalSource extends PhotoSource { if (nameIndex >= 0) { data.title = cursor.getString(nameIndex); } else { - data.title = - mResources.getString(R.string.unknown_album_name, "Unknown"); + data.title = mUnknownAlbumName; } log(TAG, data.title + " found"); diff --git a/src/com/android/dreams/phototable/PhotoSource.java b/src/com/android/dreams/phototable/PhotoSource.java index 8a09bba..c2b423b 100644 --- a/src/com/android/dreams/phototable/PhotoSource.java +++ b/src/com/android/dreams/phototable/PhotoSource.java @@ -57,15 +57,17 @@ public abstract class PhotoSource { } } - public static class AlbumData { + public class AlbumData { public String id; public String title; public String thumbnailUrl; + public String account; public long updated; - @Override - public String toString() { - return title; + public String getType() { + String type = PhotoSource.this.getClass().getName(); + log(TAG, "type is " + type); + return type; } } diff --git a/src/com/android/dreams/phototable/PhotoTableDreamSettings.java b/src/com/android/dreams/phototable/PhotoTableDreamSettings.java index e7ba945..7271f3f 100644 --- a/src/com/android/dreams/phototable/PhotoTableDreamSettings.java +++ b/src/com/android/dreams/phototable/PhotoTableDreamSettings.java @@ -18,7 +18,7 @@ package com.android.dreams.phototable; import android.content.SharedPreferences; import android.app.ListActivity; import android.os.Bundle; -import android.widget.ArrayAdapter; +import android.widget.ListAdapter; import java.util.LinkedList; @@ -30,7 +30,7 @@ public class PhotoTableDreamSettings extends ListActivity { public static final String PREFS_NAME = PhotoTableDream.TAG; private PhotoSourcePlexor mPhotoSource; - private ArrayAdapter<PhotoSource.AlbumData> mAdapter; + private ListAdapter mAdapter; private SharedPreferences mSettings; @Override @@ -42,11 +42,11 @@ public class PhotoTableDreamSettings extends ListActivity { mSettings = getSharedPreferences(PREFS_NAME, 0); mPhotoSource = new PhotoSourcePlexor(this, mSettings); - mAdapter = new AlbumDataAdapter(this, + mAdapter = new SectionedAlbumDataAdapter(this, mSettings, + R.layout.header, R.layout.album, new LinkedList<PhotoSource.AlbumData>(mPhotoSource.findAlbums())); - mAdapter.sort(new AlbumDataAdapter.RecencyComparator()); setListAdapter(mAdapter); } } diff --git a/src/com/android/dreams/phototable/PicasaSource.java b/src/com/android/dreams/phototable/PicasaSource.java index af57fd1..cd5ddcd 100644 --- a/src/com/android/dreams/phototable/PicasaSource.java +++ b/src/com/android/dreams/phototable/PicasaSource.java @@ -38,6 +38,7 @@ public class PicasaSource extends PhotoSource { private static final String PICASA_PHOTO_PATH = "photos"; private static final String PICASA_ALBUM_PATH = "albums"; + private static final String PICASA_USER_PATH = "users"; private static final String PICASA_ID = "_id"; private static final String PICASA_URL = "content_url"; @@ -48,6 +49,7 @@ public class PicasaSource extends PhotoSource { private static final String PICASA_ALBUM_TYPE = "album_type"; private static final String PICASA_ALBUM_USER = "user_id"; private static final String PICASA_ALBUM_UPDATED = "date_updated"; + private static final String PICASA_ACCOUNT = "account"; private static final String PICASA_URL_KEY = "content_url"; private static final String PICASA_TYPE_KEY = "type"; @@ -59,6 +61,9 @@ public class PicasaSource extends PhotoSource { private static final String PICASA_UPLOAD_TYPE = "InstantUpload"; private final int mMaxPostAblums; + private final String mPostsAlbumName; + private final String mUploadsAlbumName; + private final String mUnknownAlbumName; private int mNextPosition; @@ -67,6 +72,9 @@ public class PicasaSource extends PhotoSource { mSourceName = TAG; mNextPosition = -1; mMaxPostAblums = mResources.getInteger(R.integer.max_post_albums); + mPostsAlbumName = mResources.getString(R.string.posts_album_name, "Posts"); + mUploadsAlbumName = mResources.getString(R.string.uploads_album_name, "Instant Uploads"); + mUnknownAlbumName = mResources.getString(R.string.unknown_album_name, "Unknown"); log(TAG, "mSettings: " + mSettings); fillQueue(); } @@ -157,6 +165,27 @@ public class PicasaSource extends PhotoSource { return foundImages; } + private String resolveAccount(String id) { + String displayName = "unknown"; + String[] projection = {PICASA_ACCOUNT}; + Uri.Builder picasaUriBuilder = new Uri.Builder() + .scheme("content") + .authority(PICASA_AUTHORITY) + .appendPath(PICASA_USER_PATH) + .appendPath(id); + Cursor cursor = mResolver.query(picasaUriBuilder.build(), + projection, null, null, null); + if (cursor != null) { + cursor.moveToFirst(); + int accountIndex = cursor.getColumnIndex(PICASA_ACCOUNT); + if (accountIndex >= 0) { + displayName = cursor.getString(accountIndex); + } + cursor.close(); + } + return displayName; + } + private Collection<String> resolveAlbumIds(String id) { LinkedList<String> albumIds = new LinkedList<String>(); log(TAG, "resolving " + id); @@ -169,7 +198,7 @@ public class PicasaSource extends PhotoSource { String[] projection = {PICASA_ID, PICASA_ALBUM_TYPE, PICASA_ALBUM_UPDATED, PICASA_ALBUM_USER}; String order = PICASA_ALBUM_UPDATED + " DESC"; - String selection = (PICASA_ALBUM_USER + " = '" + parts[2] + "' AND " + + String selection = (PICASA_ALBUM_USER + " = '" + parts[2] + "' AND " + PICASA_ALBUM_TYPE + " = '" + parts[1] + "'"); Uri.Builder picasaUriBuilder = new Uri.Builder() .scheme("content") @@ -201,6 +230,7 @@ public class PicasaSource extends PhotoSource { public Collection<AlbumData> findAlbums() { log(TAG, "finding albums"); HashMap<String, AlbumData> foundAlbums = new HashMap<String, AlbumData>(); + HashMap<String, String> accounts = new HashMap<String, String>(); String[] projection = {PICASA_ID, PICASA_TITLE, PICASA_THUMB, PICASA_ALBUM_TYPE, PICASA_ALBUM_USER, PICASA_ALBUM_UPDATED}; Uri.Builder picasaUriBuilder = new Uri.Builder() @@ -230,6 +260,12 @@ public class PicasaSource extends PhotoSource { boolean isPosts = (typeIndex >= 0 && PICASA_POSTS_TYPE.equals(type)); boolean isUpload = (typeIndex >= 0 && PICASA_UPLOAD_TYPE.equals(type)); + String account = accounts.get(user); + if (account == null) { + account = resolveAccount(user); + accounts.put(user, account); + } + if (isPosts) { id = TAG + ":" + PICASA_POSTS_TYPE + ":" + user; } @@ -244,19 +280,16 @@ public class PicasaSource extends PhotoSource { if (data == null) { data = new AlbumData(); data.id = id; + data.account = account; if (isPosts) { - data.title = - mResources.getString(R.string.posts_album_name, "Posts"); + data.title = mPostsAlbumName; } else if (isUpload) { - data.title = - mResources.getString(R.string.uploads_album_name, - "Instant Uploads"); + data.title = mUploadsAlbumName; } else if (titleIndex >= 0) { data.title = cursor.getString(titleIndex); } else { - data.title = - mResources.getString(R.string.unknown_album_name, "Unknown"); + data.title = mUnknownAlbumName; } if (thumbIndex >= 0) { diff --git a/src/com/android/dreams/phototable/SectionedAlbumDataAdapter.java b/src/com/android/dreams/phototable/SectionedAlbumDataAdapter.java new file mode 100644 index 0000000..56fd954 --- /dev/null +++ b/src/com/android/dreams/phototable/SectionedAlbumDataAdapter.java @@ -0,0 +1,204 @@ +/* + * 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. + */ +package com.android.dreams.phototable; + +import android.content.Context; +import android.content.SharedPreferences; +import android.database.DataSetObserver; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.ListAdapter; + +import java.util.Arrays; +import java.util.List; + +/** + * Settings panel for photo flipping dream. + */ +public class SectionedAlbumDataAdapter extends DataSetObserver implements ListAdapter { + private static final String TAG = "SectionedAlbumDataAdapter"; + private static final boolean DEBUG = true; + + private final LayoutInflater mInflater; + private final int mLayout; + private final AlbumDataAdapter mAlbumData; + private final Context mContext; + private int[] sections; + + public SectionedAlbumDataAdapter(Context context, SharedPreferences settings, + int headerLayout, int itemLayout, List<PhotoSource.AlbumData> objects) { + mLayout = headerLayout; + mContext = context; + mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mAlbumData = new AlbumDataAdapter(context, settings, itemLayout, objects); + mAlbumData.sort(new AlbumDataAdapter.AccountComparator()); + onChanged(); + mAlbumData.registerDataSetObserver(this); + } + + // DataSetObserver + + @Override + public void onChanged() { + if (DEBUG) Log.i(TAG, "onChanged"); + int numSections = 0; + String previous = ""; + if (DEBUG) Log.i(TAG, "numAlbums = " + mAlbumData.getCount()); + for (int i = 0; i < mAlbumData.getCount(); i++) { + PhotoSource.AlbumData item = mAlbumData.getItem(i); + if (previous.isEmpty() || !previous.equals(item.account)) { + if (DEBUG) Log.i(TAG, "previous = " + previous +", title = " + item.account); + previous = item.account; + numSections++; + } + } + + if (DEBUG) Log.i(TAG, "numSections = " + numSections); + sections = new int[numSections]; + numSections = 0; + previous = ""; + + for (int i = 0; i < mAlbumData.getCount(); i++) { + PhotoSource.AlbumData item = mAlbumData.getItem(i); + if (previous.isEmpty() || !previous.equals(item.account)) { + previous = item.account; + sections[numSections] = i; + numSections++; + } + } + + for (int i = 0; i < sections.length; i++) { + sections[i] += i; + if (DEBUG) Log.i(TAG, i + ": " + sections[i]); + } + } + + @Override + public void onInvalidated() { + onChanged(); + } + + // ListAdapter + + @Override + public boolean areAllItemsEnabled() { + return mAlbumData.areAllItemsEnabled(); + } + + @Override + public boolean isEnabled(int position) { + if (isHeader(position)) { + return false; + } else { + return mAlbumData.isEnabled(internalPosition(position)); + } + } + + // Adapter + + @Override + public int getCount() { + return mAlbumData.getCount() + sections.length; + } + + @Override + public Object getItem(int position) { + if (isHeader(position)) { + return mAlbumData.getItem(internalPosition(position+1)).account; + } else { + return mAlbumData.getItem(internalPosition(position)); + } + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemViewType(int position) { + if (isHeader(position)) { + return mAlbumData.getViewTypeCount(); + } else { + return mAlbumData.getItemViewType(internalPosition(position)); + } + } + + @Override + public int getViewTypeCount() { + return mAlbumData.getViewTypeCount() + 1; + } + + @Override + public boolean hasStableIds() { + return mAlbumData.hasStableIds(); + } + + @Override + public boolean isEmpty() { + return mAlbumData.isEmpty(); + } + + @Override + public void registerDataSetObserver(DataSetObserver observer) { + mAlbumData.registerDataSetObserver(observer); + } + + @Override + public void unregisterDataSetObserver(DataSetObserver observer) { + mAlbumData.unregisterDataSetObserver(observer); + } + + @Override + public View getView (int position, View convertView, ViewGroup parent) { + if (isHeader(position)) { + if (DEBUG) Log.i(TAG, "header at " + position); + View item = convertView; + if (item == null) { + item = mInflater.inflate(mLayout, parent, false); + } + View vTextView = item.findViewById(R.id.title); + if (vTextView != null && vTextView instanceof TextView) { + TextView textView = (TextView) vTextView; + textView.setText((String) getItem(position)); + } + return item; + } else { + if (DEBUG) Log.i(TAG, "non-header at " + position + + " fetching " + internalPosition(position)); + View item = mAlbumData.getView(internalPosition(position), convertView, parent); + return item; + } + } + + // internal + + private boolean isHeader(int position) { + return (Arrays.binarySearch(sections, position) >= 0); + } + + private int internalPosition(int position) { + int offset = Arrays.binarySearch(sections, position); + if (offset < 0) { + offset = -(offset + 1); + } + return position - offset; + } +} diff --git a/src/com/android/dreams/phototable/StockSource.java b/src/com/android/dreams/phototable/StockSource.java index d7c6d23..fff7e61 100644 --- a/src/com/android/dreams/phototable/StockSource.java +++ b/src/com/android/dreams/phototable/StockSource.java @@ -46,11 +46,15 @@ public class StockSource extends PhotoSource { private final LinkedList<ImageData> mImageList; private final LinkedList<AlbumData> mAlbumList; + private final String mStockPhotoName; + private final String mStockThumbnail; private int mNextPosition; public StockSource(Context context, SharedPreferences settings) { super(context, settings); mSourceName = TAG; + mStockPhotoName = mResources.getString(R.string.stock_photo_album_name, "Default Photos"); + mStockThumbnail = mResources.getString(R.string.stock_photo_thumbnail_url); mImageList = new LinkedList<ImageData>(); mAlbumList = new LinkedList<AlbumData>(); fillQueue(); @@ -61,8 +65,9 @@ public class StockSource extends PhotoSource { if (mAlbumList.isEmpty()) { AlbumData data = new AlbumData(); data.id = ALBUM_ID; - data.title = mResources.getString(R.string.stock_photo_album_name, "Default Photos"); - data.thumbnailUrl = mResources.getString(R.string.stock_photo_thumbnail_url); + data.account = mStockPhotoName; + data.title = mStockPhotoName; + data.thumbnailUrl = mStockThumbnail; mAlbumList.offer(data); } log(TAG, "returning a list of albums: " + mAlbumList.size()); |