1c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren/*
2c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * Copyright (C) 2012 The Android Open Source Project
3c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren *
4c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * Licensed under the Apache License, Version 2.0 (the "License");
5c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * you may not use this file except in compliance with the License.
6c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * You may obtain a copy of the License at
7c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren *
8c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren *      http://www.apache.org/licenses/LICENSE-2.0
9c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren *
10c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * Unless required by applicable law or agreed to in writing, software
11c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * distributed under the License is distributed on an "AS IS" BASIS,
12c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * See the License for the specific language governing permissions and
14c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren * limitations under the License.
15c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren */
16c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenpackage com.android.dreams.phototable;
17c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
18c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenimport android.content.Context;
19d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport android.content.SharedPreferences;
20c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenimport android.database.Cursor;
21e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wrenimport android.net.ConnectivityManager;
22c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenimport android.net.Uri;
23c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wrenimport android.util.DisplayMetrics;
24146ce64b748e2393e80174240624c2e9f2b61c41Chris Wrenimport android.util.Log;
25c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wrenimport android.view.WindowManager;
26c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
27c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenimport java.io.FileNotFoundException;
28c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenimport java.io.InputStream;
29c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenimport java.io.IOException;
3083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenimport java.util.Collection;
31146ce64b748e2393e80174240624c2e9f2b61c41Chris Wrenimport java.util.Collections;
32d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wrenimport java.util.HashMap;
33c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wrenimport java.util.LinkedList;
34d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wrenimport java.util.Set;
35c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
36c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren/**
3783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren * Loads images from Picasa.
38c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren */
3983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wrenpublic class PicasaSource extends PhotoSource {
40c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    private static final String TAG = "PhotoTable.PicasaSource";
41c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
42d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_AUTHORITY =
43d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            "com.google.android.gallery3d.GooglePhotoProvider";
44d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
45d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_PHOTO_PATH = "photos";
46d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_ALBUM_PATH = "albums";
47e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private static final String PICASA_USER_PATH = "users";
48d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
49c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    private static final String PICASA_ID = "_id";
50c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    private static final String PICASA_URL = "content_url";
51c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    private static final String PICASA_ROTATION = "rotation";
52c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    private static final String PICASA_ALBUM_ID = "album_id";
53d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_TITLE = "title";
54d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_THUMB = "thumbnail_url";
55d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_ALBUM_TYPE = "album_type";
56c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren    private static final String PICASA_ALBUM_USER = "user_id";
57d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_ALBUM_UPDATED = "date_updated";
58e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private static final String PICASA_ACCOUNT = "account";
59c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
60c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    private static final String PICASA_URL_KEY = "content_url";
61c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    private static final String PICASA_TYPE_KEY = "type";
62d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_TYPE_FULL_VALUE = "full";
63d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_TYPE_SCREEN_VALUE = "screennail";
64d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_TYPE_THUMB_VALUE = "thumbnail";
65d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private static final String PICASA_TYPE_IMAGE_VALUE = "image";
66c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren    private static final String PICASA_POSTS_TYPE = "Buzz";
67c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren    private static final String PICASA_UPLOAD_TYPE = "InstantUpload";
68c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
69d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private final int mMaxPostAblums;
70e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private final String mPostsAlbumName;
71e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private final String mUploadsAlbumName;
72e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private final String mUnknownAlbumName;
73e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren    private final LinkedList<ImageData> mRecycleBin;
74e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren    private final ConnectivityManager mConnectivityManager;
75e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren    private final int mMaxRecycleSize;
76c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
77d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren    private Set<String> mFoundAlbumIds;
78d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    private int mNextPosition;
79c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren    private int mDisplayLongSide;
8083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren
81d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    public PicasaSource(Context context, SharedPreferences settings) {
82d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        super(context, settings);
8383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        mSourceName = TAG;
84c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        mNextPosition = -1;
85d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        mMaxPostAblums = mResources.getInteger(R.integer.max_post_albums);
86e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        mPostsAlbumName = mResources.getString(R.string.posts_album_name, "Posts");
87e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        mUploadsAlbumName = mResources.getString(R.string.uploads_album_name, "Instant Uploads");
88e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        mUnknownAlbumName = mResources.getString(R.string.unknown_album_name, "Unknown");
89e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren        mMaxRecycleSize = mResources.getInteger(R.integer.recycle_image_pool_size);
90e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren        mConnectivityManager =
91e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
92e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren        mRecycleBin = new LinkedList<ImageData>();
93c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        fillQueue();
94c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren        mDisplayLongSide = getDisplayLongSide();
95c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren    }
96c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren
97c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren    private int getDisplayLongSide() {
98c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren        DisplayMetrics metrics = new DisplayMetrics();
99c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren        WindowManager wm = (WindowManager)
100c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren                mContext.getSystemService(Context.WINDOW_SERVICE);
101c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren        wm.getDefaultDisplay().getMetrics(metrics);
102c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren        return Math.max(metrics.heightPixels, metrics.widthPixels);
103c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    }
104c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
10583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    @Override
10683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    protected Collection<ImageData> findImages(int howMany) {
10783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        log(TAG, "finding images");
10883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        LinkedList<ImageData> foundImages = new LinkedList<ImageData>();
109e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren        if (mConnectivityManager.isActiveNetworkMetered()) {
110e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            howMany = Math.min(howMany, mMaxRecycleSize);
111e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            log(TAG, "METERED: " + howMany);
112e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            if (!mRecycleBin.isEmpty()) {
113e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                foundImages.addAll(mRecycleBin);
114e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                log(TAG, "recycled " + foundImages.size() + " items.");
115e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                return foundImages;
116e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            }
117e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren        }
118e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren
119c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        String[] projection = {PICASA_ID, PICASA_URL, PICASA_ROTATION, PICASA_ALBUM_ID};
120d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        boolean usePosts = false;
121c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        LinkedList<String> albumIds = new LinkedList<String>();
122d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        for (String id : getFoundAlbums()) {
123d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren            if (mSettings.isAlbumEnabled(id)) {
124d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                String[] parts = id.split(":");
125c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                if (parts.length > 2) {
126c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    albumIds.addAll(resolveAlbumIds(id));
127c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                } else {
128c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    albumIds.add(parts[1]);
129d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                }
130c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            }
131c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        }
132c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren
133146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        if (albumIds.size() > mMaxPostAblums) {
134146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            Collections.shuffle(albumIds);
135146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        }
136146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren
137c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        StringBuilder selection = new StringBuilder();
138146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        int albumIdx = 0;
139c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        for (String albumId : albumIds) {
140146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            if (albumIdx < mMaxPostAblums) {
141d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                if (selection.length() > 0) {
142d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    selection.append(" OR ");
143d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                }
144c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                log(TAG, "adding: " + albumId);
145146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                selection.append(PICASA_ALBUM_ID + " = '" + albumId + "'");
146146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            } else {
147146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                log(TAG, "too many albums, dropping: " + albumId);
148d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            }
149146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            albumIdx++;
150d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
151d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
152d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        if (selection.length() == 0) {
153d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            return foundImages;
154d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
155c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren
156146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        log(TAG, "selection is (" + selection.length() + "): " + selection.toString());
157d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
158c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        Uri.Builder picasaUriBuilder = new Uri.Builder()
159c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                .scheme("content")
160d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .authority(PICASA_AUTHORITY)
161d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .appendPath(PICASA_PHOTO_PATH);
162c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        Cursor cursor = mResolver.query(picasaUriBuilder.build(),
163d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                projection, selection.toString(), null, null);
164c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        if (cursor != null) {
16583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            if (cursor.getCount() > howMany && mNextPosition == -1) {
166c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                mNextPosition =
16783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                        (int) Math.abs(mRNG.nextInt() % (cursor.getCount() - howMany));
168c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            }
169c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            if (mNextPosition == -1) {
170c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                mNextPosition = 0;
171c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            }
17283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            log(TAG, "moving to position: " + mNextPosition);
173c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            cursor.moveToPosition(mNextPosition);
174c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
175c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            int idIndex = cursor.getColumnIndex(PICASA_ID);
176c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            int urlIndex = cursor.getColumnIndex(PICASA_URL);
177c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            int orientationIndex = cursor.getColumnIndex(PICASA_ROTATION);
178c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            int bucketIndex = cursor.getColumnIndex(PICASA_ALBUM_ID);
179c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
180c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            if (idIndex < 0) {
18183fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                log(TAG, "can't find the ID column!");
182c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            } else {
18383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                while (foundImages.size() < howMany && !cursor.isAfterLast()) {
184c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                    if (idIndex >= 0) {
185c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                        ImageData data = new ImageData();
186c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                        data.id = cursor.getString(idIndex);
187c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
188c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                        if (urlIndex >= 0) {
189c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                            data.url = cursor.getString(urlIndex);
190c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                        }
191c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
19283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                        foundImages.offer(data);
193c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                    }
194c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                    if (cursor.moveToNext()) {
195c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                        mNextPosition++;
196c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                    }
197c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                }
198c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                if (cursor.isAfterLast()) {
199c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                    mNextPosition = 0;
200c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren                }
201c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            }
202c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
203c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            cursor.close();
204146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        } else {
205146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            Log.w(TAG, "received a null cursor in findImages()");
206c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        }
20783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        log(TAG, "found " + foundImages.size() + " items.");
20883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        return foundImages;
209c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    }
210c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
211e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    private String resolveAccount(String id) {
212e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        String displayName = "unknown";
213e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        String[] projection = {PICASA_ACCOUNT};
214e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        Uri.Builder picasaUriBuilder = new Uri.Builder()
215e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                .scheme("content")
216e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                .authority(PICASA_AUTHORITY)
217e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                .appendPath(PICASA_USER_PATH)
218e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                .appendPath(id);
219e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        Cursor cursor = mResolver.query(picasaUriBuilder.build(),
220e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                projection, null, null, null);
221e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        if (cursor != null) {
222e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            cursor.moveToFirst();
223e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            int accountIndex = cursor.getColumnIndex(PICASA_ACCOUNT);
224e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            if (accountIndex >= 0) {
225e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                displayName = cursor.getString(accountIndex);
226e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            }
227e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren            cursor.close();
228146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        } else {
229146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            Log.w(TAG, "received a null cursor in resolveAccount()");
230e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        }
231e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        return displayName;
232e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren    }
233e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren
234c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren    private Collection<String> resolveAlbumIds(String id) {
235c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        LinkedList<String> albumIds = new LinkedList<String>();
236c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        log(TAG, "resolving " + id);
237c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren
238c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        String[] parts = id.split(":");
239c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        if (parts.length < 3) {
240c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren            return albumIds;
241c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        }
242c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren
243c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        String[] projection = {PICASA_ID, PICASA_ALBUM_TYPE, PICASA_ALBUM_UPDATED,
244c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                               PICASA_ALBUM_USER};
245d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        String order = PICASA_ALBUM_UPDATED + " DESC";
246e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        String selection = (PICASA_ALBUM_USER + " = '" + parts[2] + "' AND " +
247c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                            PICASA_ALBUM_TYPE + " = '" + parts[1] + "'");
248d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        Uri.Builder picasaUriBuilder = new Uri.Builder()
249d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .scheme("content")
250d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .authority(PICASA_AUTHORITY)
251d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .appendPath(PICASA_ALBUM_PATH)
252d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .appendQueryParameter(PICASA_TYPE_KEY, PICASA_TYPE_IMAGE_VALUE);
253d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        Cursor cursor = mResolver.query(picasaUriBuilder.build(),
254c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                projection, selection, null, order);
255d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        if (cursor != null) {
256146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            log(TAG, " " + id + " resolved to " + cursor.getCount() + " albums");
257d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            cursor.moveToFirst();
258d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
259d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int idIndex = cursor.getColumnIndex(PICASA_ID);
260d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int typeIndex = cursor.getColumnIndex(PICASA_ALBUM_TYPE);
261d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
262d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            if (idIndex < 0) {
263d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                log(TAG, "can't find the ID column!");
264d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            } else {
265c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                while (!cursor.isAfterLast()) {
266c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    albumIds.add(cursor.getString(idIndex));
267d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    cursor.moveToNext();
268d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                }
269d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            }
270d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            cursor.close();
271146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        } else {
272146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            Log.w(TAG, "received a null cursor in resolveAlbumIds()");
273d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
274c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren        return albumIds;
275d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    }
276d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
277d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren    private Set<String> getFoundAlbums() {
278d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        if (mFoundAlbumIds == null) {
279d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren            findAlbums();
280d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        }
281d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        return mFoundAlbumIds;
282d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren    }
283d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren
284d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    @Override
285d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    public Collection<AlbumData> findAlbums() {
286d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        log(TAG, "finding albums");
287d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        HashMap<String, AlbumData> foundAlbums = new HashMap<String, AlbumData>();
288e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren        HashMap<String, String> accounts = new HashMap<String, String>();
289d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        String[] projection = {PICASA_ID, PICASA_TITLE, PICASA_THUMB, PICASA_ALBUM_TYPE,
290c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                               PICASA_ALBUM_USER, PICASA_ALBUM_UPDATED};
291d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        Uri.Builder picasaUriBuilder = new Uri.Builder()
292d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .scheme("content")
293d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .authority(PICASA_AUTHORITY)
294d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .appendPath(PICASA_ALBUM_PATH)
295d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                .appendQueryParameter(PICASA_TYPE_KEY, PICASA_TYPE_IMAGE_VALUE);
296d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        Cursor cursor = mResolver.query(picasaUriBuilder.build(),
297d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                projection, null, null, null);
298d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        if (cursor != null) {
299d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            cursor.moveToFirst();
300d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
301d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int idIndex = cursor.getColumnIndex(PICASA_ID);
302d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int thumbIndex = cursor.getColumnIndex(PICASA_THUMB);
303d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int titleIndex = cursor.getColumnIndex(PICASA_TITLE);
304d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int typeIndex = cursor.getColumnIndex(PICASA_ALBUM_TYPE);
305d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            int updatedIndex = cursor.getColumnIndex(PICASA_ALBUM_UPDATED);
306c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren            int userIndex = cursor.getColumnIndex(PICASA_ALBUM_USER);
307d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
308d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            if (idIndex < 0) {
309d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                log(TAG, "can't find the ID column!");
310d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            } else {
311d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                while (!cursor.isAfterLast()) {
312d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    String id = TAG + ":" + cursor.getString(idIndex);
313c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    String user = (userIndex >= 0 ? cursor.getString(userIndex) : "-1");
314c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    String type = (typeIndex >= 0 ? cursor.getString(typeIndex) : "none");
315c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    boolean isPosts = (typeIndex >= 0 && PICASA_POSTS_TYPE.equals(type));
316c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    boolean isUpload = (typeIndex >= 0 && PICASA_UPLOAD_TYPE.equals(type));
317c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren
318e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                    String account = accounts.get(user);
319e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                    if (account == null) {
320e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                        account = resolveAccount(user);
321e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                        accounts.put(user, account);
322e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                    }
323e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren
324c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    if (isPosts) {
325146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                        log(TAG, "replacing " + id + " with " + PICASA_POSTS_TYPE);
326c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                        id = TAG + ":" + PICASA_POSTS_TYPE + ":" + user;
327c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    }
328d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
329c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    if (isUpload) {
330146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                        log(TAG, "replacing " + id + " with " + PICASA_UPLOAD_TYPE);
331c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                        id = TAG + ":" + PICASA_UPLOAD_TYPE + ":" + user;
332d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    }
333c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren
334c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    String thumbnailUrl = null;
335c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    long updated = 0;
3365b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren                    AlbumData data = foundAlbums.get(id);
3375b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren                    if (data == null) {
3385b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren                        data = new AlbumData();
339d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        data.id = id;
340e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                        data.account = account;
341d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
342c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                        if (isPosts) {
343e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                            data.title = mPostsAlbumName;
344c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                        } else if (isUpload) {
345e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                            data.title = mUploadsAlbumName;
346d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        } else if (titleIndex >= 0) {
347d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                            data.title = cursor.getString(titleIndex);
348d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        } else {
349e38c0c80e3e9b3b835e5c2e014ccf23e29663396Chris Wren                            data.title = mUnknownAlbumName;
350d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        }
351d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
352c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                        log(TAG, "found " + data.title + "(" + data.id + ")" +
353146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                                " of type " + type + " owned by " + user);
354d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                        foundAlbums.put(id, data);
355d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    }
356d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
3575b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren                    if (updatedIndex >= 0) {
358146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                        updated = cursor.getLong(updatedIndex);
359c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    }
360c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren
361146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                    if (thumbIndex >= 0) {
362146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                        thumbnailUrl = cursor.getString(thumbIndex);
363146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                    }
364146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren
365146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren                    data.updated = (long) Math.max(data.updated, updated);
366146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren
367c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                    if (data.thumbnailUrl == null || data.updated == updated) {
368c6175b1e065fb544ea3744a991a33304abc2f8edChris Wren                        data.thumbnailUrl = thumbnailUrl;
3695b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren                    }
3705b4b44688dac0053be77b282b7501bd291efb0d3Chris Wren
371d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    cursor.moveToNext();
372d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                }
373d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            }
374d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren            cursor.close();
375d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
376146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren        } else {
377146ce64b748e2393e80174240624c2e9f2b61c41Chris Wren            Log.w(TAG, "received a null cursor in findAlbums()");
378d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        }
379d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        log(TAG, "found " + foundAlbums.size() + " items.");
380d9b659aa5dfa4a3af96582ae49ba9ae145854a84Chris Wren        mFoundAlbumIds = foundAlbums.keySet();
381d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren        return foundAlbums.values();
382d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren    }
383d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren
38483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren    @Override
385c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren    protected InputStream getStream(ImageData data, int longSide) {
38683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        InputStream is = null;
38783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        try {
38883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            Uri.Builder photoUriBuilder = new Uri.Builder()
38983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                    .scheme("content")
390d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    .authority(PICASA_AUTHORITY)
391d85f53c69dead1f1f6c0290b8104422143bc5166Chris Wren                    .appendPath(PICASA_PHOTO_PATH)
392e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                    .appendPath(data.id);
393c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren            if (mConnectivityManager.isActiveNetworkMetered() ||
394c6bebae5e07c0108294d05e33fbace209d2f9b0dChris Wren                    ((2 * longSide) <= mDisplayLongSide)) {
395e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                photoUriBuilder.appendQueryParameter(PICASA_TYPE_KEY, PICASA_TYPE_SCREEN_VALUE);
396e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            } else {
397e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                photoUriBuilder.appendQueryParameter(PICASA_TYPE_KEY, PICASA_TYPE_FULL_VALUE);
398e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            }
39983fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            if (data.url != null) {
40083fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren                photoUriBuilder.appendQueryParameter(PICASA_URL_KEY, data.url);
401c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren            }
40283fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            is = mResolver.openInputStream(photoUriBuilder.build());
40383fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        } catch (FileNotFoundException fnf) {
40483fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            log(TAG, "file not found: " + fnf);
40583fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            is = null;
40683fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        } catch (IOException ioe) {
40783fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            log(TAG, "i/o exception: " + ioe);
40883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren            is = null;
409c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren        }
410c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren
411e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren        if (is != null) {
412e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            mRecycleBin.offer(data);
413e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            log(TAG, "RECYCLED");
414e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            while (mRecycleBin.size() > mMaxRecycleSize) {
415e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren                mRecycleBin.poll();
416e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren            }
417e8f4d55d6895e1f2bc298ef8978e1aef43ff57c5Chris Wren        }
41883fee9012b6d5c5940de5b96fe8d98653ba14c0dChris Wren        return is;
419c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren    }
420c1501041b64faa6c205a93baf403c4c87a0c1acfChris Wren}
421