public interface CropWallpaperExecutor {
	public void onPreExecute();

	public void onPostExecuteSuccess(final Intent intent);

	public void onPostExecuteError();

	public void onPostExecuteFinish();
}
 public class FilePhoto extends Photo {

	private String path;
	private boolean cached;

	public FilePhoto(String path) {
		this.path = path;
		cached = false;
	}

	public FilePhoto(Photo photo, String path) {
		super(photo);
		this.path = path;
		this.cached = true;
	}

	private FilePhoto(Parcel in) {
		super(in);
		path = in.readString();
		cached = Boolean.parseBoolean(in.readString());
	}

	@Override
	public String getUrl(PhotoSize photoSize) {
		return path;
	}

	@Override
	public boolean isScaled() {
		return true;
	}

	public boolean isCached() {
		return cached;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		super.writeToParcel(dest, flags);
		dest.writeString(path);
		dest.writeString(Boolean.toString(cached));
	}

	public static final Parcelable.Creator<FilePhoto> CREATOR = new Parcelable.Creator<FilePhoto>() {
		public FilePhoto createFromParcel(Parcel in) {
			return new FilePhoto(in);
		}

		public FilePhoto[] newArray(int size) {
			return new FilePhoto[size];
		}
	};
}
 public class Photo implements Parcelable, FlickrConstants {
	// private static final String TAG = "Photo";

	private int id;
	private String photoId;
	private String secret;
	private String server;
	private String farm;
	private String title;
	private String date;

	private String tags;
	private UserInfo userInfo;

	private String urlPattern;
	private SourceType sourceType;

	public Photo() {
		userInfo = new UserInfo();
	}

	public Photo(Photo photo) {
		id = photo.id;
		photoId = photo.photoId;
		secret = photo.secret;
		server = photo.server;
		farm = photo.farm;
		title = photo.title;
		date = photo.date;
		tags = photo.tags;
		urlPattern = photo.urlPattern;
		sourceType = photo.sourceType;
		userInfo = new UserInfo(photo.userInfo);
	}

	protected Photo(Parcel in) {
		id = in.readInt();
		photoId = in.readString();
		secret = in.readString();
		server = in.readString();
		farm = in.readString();
		title = in.readString();
		date = in.readString();
		tags = in.readString();
		urlPattern = in.readString();
		String val = in.readString();
		if (val != null) {
			sourceType = SourceType.valueOf(val);
		}
		userInfo = new UserInfo(in);
	}

	/**
	 * Returns the title of the photo, if specified.
	 * 
	 * @return The title of the photo. The returned value can be empty or null.
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * Returns the date at which the photo was taken, formatted in the current
	 * locale with the following pattern: MMMM d, yyyy.
	 * 
	 * @return The title of the photo. The returned value can be empty or null.
	 */
	public String getDate() {
		return date;
	}

	/**
	 * Returns the URL to the photo for the specified size.
	 * 
	 * @param photoSize
	 *            The required size of the photo.
	 * 
	 * @return A URL to the photo for the specified size.
	 * 
	 * @see com.koonen.photostream.Flickr.PhotoSize
	 */
	public String getUrl(PhotoSize photoSize) {
		return String.format(urlPattern, photoSize.size());
	}

	@Override
	public String toString() {
		return title + ", " + date + " @" + photoId;
	}

	public int describeContents() {
		return 0;
	}

	public void writeToParcel(Parcel dest, int flags) {
		dest.writeInt(id);
		dest.writeString(photoId);
		dest.writeString(secret);
		dest.writeString(server);
		dest.writeString(farm);
		dest.writeString(title);
		dest.writeString(date);
		dest.writeString(tags);
		dest.writeString(urlPattern);
		dest.writeString(sourceType == null ? null : sourceType.getValue());
		userInfo.writeToParcel(dest, flags);
	}

	public static final Parcelable.Creator<Photo> CREATOR = new Parcelable.Creator<Photo>() {
		public Photo createFromParcel(Parcel in) {
			return new Photo(in);
		}

		public Photo[] newArray(int size) {
			return new Photo[size];
		}
	};

	public String getPhotoId() {
		return photoId;
	}

	public void setPhotoId(String photoId) {
		this.photoId = photoId;
	}

	public String getSecret() {
		return secret;
	}

	public void setSecret(String secret) {
		this.secret = secret;
	}

	public String getServer() {
		return server;
	}

	public void setServer(String server) {
		this.server = server;
	}

	public String getFarm() {
		return farm;
	}

	public void setFarm(String farm) {
		this.farm = farm;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public void setDate(String date) {
		this.date = date;
	}

	public String getTags() {
		return tags;
	}

	public void setTags(String tags) {
		this.tags = tags;
	}

	public String getUrlPattern() {
		return urlPattern;
	}

	public void setUrlPattern(String urlPattern) {
		this.urlPattern = urlPattern;
	}

	public SourceType getSourceType() {
		return sourceType;
	}

	public void setSourceType(SourceType sourceType) {
		this.sourceType = sourceType;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public UserInfo getUserInfo() {
		return userInfo;
	}

	public void setUserInfo(UserInfo userInfo) {
		this.userInfo = userInfo;
	}

	public boolean isScaled() {
		return false;
	}
} public class PhotoList {
	private List<Photo> photos;
	private int page;
	private int pageCount;

	public PhotoList() {
		photos = new ArrayList<Photo>();
	}

	public void add(Photo photo) {
		photos.add(photo);
	}

	/**
	 * Returns the photo at the specified index in the current set. An
	 * {@link ArrayIndexOutOfBoundsException} can be thrown if the index is less
	 * than 0 or greater then or equals to {@link #getCount()}.
	 * 
	 * @param index
	 *            The index of the photo to retrieve from the list.
	 * 
	 * @return A valid {@link com.koonen.photostream.Flickr.Photo}.
	 */
	public Photo get(int index) {
		return photos.get(index);
	}

	/**
	 * Returns the number of photos in the list.
	 * 
	 * @return A positive integer, or 0 if the list is empty.
	 */
	public int getCount() {
		return photos != null ? photos.size() : 0;
	}

	/**
	 * Returns the page index of the photos from this list.
	 * 
	 * @return The index of the Flickr page that contains the photos of this
	 *         list.
	 */
	public int getPage() {
		return page;
	}

	/**
	 * Returns the total number of photo pages.
	 * 
	 * @return A positive integer, or 0 if the photostream is empty.
	 */
	public int getPageCount() {
		return pageCount;
	}

	public List<Photo> getPhotos() {
		return photos;
	}

	public void setPhotos(List<Photo> photos) {
		this.photos = photos;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public void setPageCount(int pageCount) {
		this.pageCount = pageCount;
	}
} public enum PhotoSize {
	/**
	 * Small square image (75x75 px).
	 */
	SMALL_SQUARE("_s", 75),
	/**
	 * Thumbnail image (the longest side measures 100 px).
	 */
	THUMBNAIL("_t", 100),
	/**
	 * Small image (the longest side measures 240 px).
	 */
	SMALL("_m", 240),
	/**
	 * Medium image (the longest side measures 500 px).
	 */
	MEDIUM("", 500),
	/**
	 * Large image (the longest side measures 1024 px).
	 */
	LARGE("_b", 1024),

	ORIGINAL("_o", 0);

	private final String mSize;
	private final int mLongSide;

	private PhotoSize(String size, int longSide) {
		mSize = size;
		mLongSide = longSide;
	}

	/**
	 * Returns the size in pixels of the longest side of the image.
	 * 
	 * @return THe dimension in pixels of the longest side.
	 */
	int longSide() {
		return mLongSide;
	}

	/**
	 * Returns the name of the size, as defined by Flickr. For instance, the
	 * LARGE size is defined by the String "_b".
	 * 
	 * @return
	 */
	String size() {
		return mSize;
	}

	@Override
	public String toString() {
		return name() + ", longSide=" + mLongSide;
	}
} public class ServiceContext implements Parcelable {

	private static final String SEARCH_TITLE_FORMAT_QUERY_GROUP = "Search: %s in %s";
	private static final String SEARCH_TITLE_FORMAT_QUERY = "Search: %s";
	private static final String SEARCH_TITLE_FORMAT_GROUP = "Search in %s";

	private String screenName;

	private Type type;

	private boolean pagable;
	private int countPages;
	private int currentPage;
	private int pageSize;
	private int countPhotos;
	private Map<String, String> extra;

	private String query;

	private PhotoList result;

	public static ServiceContext createSearchContext(int pageSize, String query) {
		return createSearchContext(pageSize, query, null);
	}

	private static ServiceContext createSearchContext(int pageSize,
			String query, String groupName) {
		ServiceContext result = new ServiceContext();
		result.setPagable(true);
		result.setPageSize(pageSize);
		result.setCurrentPage(1);
		result.type = Type.SEARCH;
		result.setQuery(query);
		result.setScreenName(generateSearchTitle(query, groupName));
		return result;
	}

	public static ServiceContext createRecentContext(int pageSize) {
		ServiceContext result = new ServiceContext();
		result.setPagable(true);
		result.setPageSize(pageSize);
		result.setCurrentPage(1);
		result.type = Type.RECENT;
		result.setScreenName("Recent photos");
		return result;
	}

	public static ServiceContext createMyNetworkContext(int pageSize, String query) {
		ServiceContext result = null;
		if (isEmpty(query)) {
			result = createMyNetworkContext(pageSize, query, Type.PERSONAL);
		} else {
			result = createMyNetworkContext(pageSize, query, Type.PERSONAL_SEARCH);
		}
		return result;
	}
	
	private static ServiceContext createMyNetworkContext(int pageSize, String query, Type type) {
		ServiceContext result = new ServiceContext();
		result.setPagable(true);
		result.setPageSize(pageSize);
		result.setCurrentPage(1);
		result.type = type;
		result.setQuery(query);
		result.setScreenName("My network photos");
		return result;
	}
	
//	public static ServiceContext createPersonalContext(int pageSize) {
//		ServiceContext result = new ServiceContext();
//		result.setPagable(true);
//		result.setPageSize(pageSize);
//		result.setCurrentPage(1);
//		result.type = Type.PERSONAL;
//		result.setScreenName("My network photos");
//		return result;
//	}
//
//	public static ServiceContext createMyTagsContext(int pageSize, String query) {
//		ServiceContext result = new ServiceContext();
//		result.setPagable(true);
//		result.setPageSize(pageSize);
//		result.setCurrentPage(1);
//		result.type = Type.PERSONAL_SEARCH;
//		result.setQuery(query);
//		result.setScreenName("My network photos");
//		return result;
//	}

	public static ServiceContext createSingleContext(
			ServiceContext serviceContext, int photoPageNumber) {
		ServiceContext result = new ServiceContext();
		result.setPagable(true);
		result.setCurrentPage(serviceContext.getPageSize()
				* (serviceContext.getCurrentPage() - 1) + photoPageNumber + 1);
		result.setPageSize(1);
		int countPages;
		if (serviceContext.getCountPages() == 1) {
			countPages = serviceContext.getCountPhotos();
		} else {
			countPages = serviceContext.getPageSize()
					* serviceContext.getCountPages();
		}
		result.setCountPages(countPages);

		for (Iterator<String> iterator = serviceContext.extra.keySet()
				.iterator(); iterator.hasNext();) {
			String name = (String) iterator.next();
			result.addParameter(name, serviceContext.extra.get(name));
		}
		result.setQuery(serviceContext.getQuery());
		result.type = serviceContext.getType();
		// result.setScreenName(serviceContext.getScreenName());
		result.setScreenName("Make this your wallpaper!");
		return result;
	}

	public static ServiceContext createFavoritesServiceContext(int pageSize) {
		ServiceContext result = new ServiceContext();
		result.setPagable(true);
		result.setPageSize(pageSize);
		result.setCurrentPage(1);
		result.type = Type.FAVORITES;
		result.setScreenName("My favorites photos");
		return result;
	}

	public static ServiceContext createCameraServiceContext() {
		ServiceContext result = new ServiceContext();
		result.setPagable(true);
		result.setPageSize(1);
		result.setCurrentPage(1);
		result.type = Type.CAMERA;
		result.setScreenName("Photo from camera");
		return result;
	}

	public static ServiceContext createCategoryContext(Category category,
			int pageSize) {
		ServiceContext result = null;
		if (category.isRecent()) {
			result = createRecentContext(pageSize);
		} else {
			result = createSearchContext(pageSize, category.getTags());
		}

		return result;
	}

	public static ServiceContext createInternalContext(int pageSize) {
		ServiceContext result = createFileSystemContext(
				Media.INTERNAL_CONTENT_URI, pageSize);
		result.type = Type.FILE_SYSTEM_INT;
		result.setScreenName("Telephone memory");
		return result;
	}

	public static ServiceContext createExternalContext(int pageSize) {
		ServiceContext result = createFileSystemContext(
				Media.EXTERNAL_CONTENT_URI, pageSize);
		result.type = Type.FILE_SYSTEM_EXT;
		result.setScreenName("SDCard");
		return result;
	}

	private static ServiceContext createFileSystemContext(Uri uri, int pageSize) {
		ServiceContext result = new ServiceContext();
		result.setPagable(true);
		result.setPageSize(pageSize);
		result.setCurrentPage(1);
		return result;
	}

	public static ServiceContext createGroupContext(String group,
			String groupName, int pageSize) {
		ServiceContext result;
		if ("".equals(group)) {
			result = ServiceContext.createRecentContext(pageSize);
		} else {
			result = ServiceContext
					.createSearchContext(pageSize, "", groupName);
		}
		return result;
	}

	private static boolean isEmpty(String string) {
		return string == null || "".equals(string);
	}

	private static String generateSearchTitle(String query, String groupName) {
		String title;
		if (!isEmpty(groupName) && !isEmpty(query)) {
			title = String.format(SEARCH_TITLE_FORMAT_QUERY_GROUP, query,
					groupName);
		} else if (!isEmpty(groupName)) {
			title = String.format(SEARCH_TITLE_FORMAT_GROUP, groupName);
		} else {
			title = String.format(SEARCH_TITLE_FORMAT_QUERY, query);
		}
		return title;
	}

	public ServiceContext() {
		extra = new HashMap<String, String>();
	}

	private ServiceContext(Parcel in) {
		this();
		type = Type.valueOf(in.readString());
		pagable = Boolean.parseBoolean(in.readString());
		countPages = in.readInt();
		currentPage = in.readInt();
		pageSize = in.readInt();
		// extra = in.readHashMap(ClassLoader.getSystemClassLoader());
		query = in.readString();
		screenName = in.readString();
	}

	public void setPagable(boolean pagable) {
		this.pagable = pagable;
	}

	public void setCountPages(int countPages) {
		this.countPages = countPages;
	}

	public void setExtra(Map<String, String> extra) {
		this.extra = extra;
	}

	public boolean isPagable() {
		return pagable;
	}

	public int getCountPages() {
		return countPages;
	}

	public void addParameter(String name, String value) {
		extra.put(name, value);
	}

	public void removeParameter(String name) {
		extra.remove(name);
	}

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public Type getType() {
		return type;
	}

	public PhotoList getResult() {
		return result;
	}

	public void setResult(PhotoList result) {
		this.result = result;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public void next() {
		currentPage++;

	}

	public void prev() {
		currentPage--;
	}

	public String getQuery() {
		return query;
	}

	public void setQuery(String query) {
		if (query != null) {
			String[] items = query.split(" ");

			StringBuilder builder = new StringBuilder();

			int count = 0;
			if (items != null) {
				count = items.length;
			}
			for (int index = 0; index < count; index++) {
				String item = items[index].trim();
				if (item.length() != 0) {
					builder.append(item);
					if (index != count - 1) {
						builder.append(",");
					}
				}

			}
			this.query = builder.toString();
		}
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(type.toString());
		dest.writeString(Boolean.toString(pagable));
		dest.writeInt(countPages);
		dest.writeInt(currentPage);
		dest.writeInt(pageSize);
		// dest.writeMap(extra);
		dest.writeString(query);
		dest.writeString(screenName);
	}

	public static final Parcelable.Creator<ServiceContext> CREATOR = new Parcelable.Creator<ServiceContext>() {
		public ServiceContext createFromParcel(Parcel in) {
			return new ServiceContext(in);
		}

		public ServiceContext[] newArray(int size) {
			return new ServiceContext[size];
		}
	};

	public String getScreenName() {
		return screenName;
	}

	public void setScreenName(String screenName) {
		this.screenName = screenName;
	}

	public boolean isNext() {
		return currentPage < countPages;
	}

	public boolean isPrev() {
		return currentPage > 1;
	}

	public boolean isRecent() {
		return type == Type.RECENT;
	}

	public int getCountPhotos() {
		return countPhotos;
	}

	public void setCountPhotos(int countPhotos) {
		this.countPhotos = countPhotos;
	}
} public class ServiceManager {

	private Context context;

	private UserPreferences userPreferences;

	private FlickrService flickrService;

	private PhotoDAO photoDAO;

	private ImageDAO imageDAO;

	private static ServiceManager instance;

	public static void init(Context context) {
		if (instance == null) {
			instance = new ServiceManager(context);
		}
	}

	public static ServiceManager get() {
		return instance;
	}

	private ServiceManager(Context context) {
		this.context = context;
		userPreferences = new UserPreferences(this.context);
		photoDAO = new PhotoDAO(this.context);
		imageDAO = new ImageDAO(this.context);
	}

	public IPhotoService getService() {
		IPhotoService service = null;
		Network network = userPreferences.getNetwork();
		if (Network.FLICKR == network) {
			service = getFlickrService();
		}

		return service;
	}

	private FlickrService getFlickrService() {
		if (flickrService == null) {
			flickrService = new FlickrService(userPreferences, photoDAO,
					imageDAO, context);
		}
		return flickrService;
	}

} public class ServiceNetworkException extends ServiceException {

	private static final long serialVersionUID = 5679809989593207185L;
	
	private static final String MESSAGE_FORMAT = "Network problem. Message details:\n{0}";

	public ServiceNetworkException(String detailMessage) {
		super(String.format(MESSAGE_FORMAT, detailMessage));
	}

	public ServiceNetworkException(String detailMessage, Throwable throwable) {
		super(String.format(MESSAGE_FORMAT, detailMessage), throwable);
	}
}
 public class UserInfo implements Parcelable {
	private String mUserId;
	private String mLocation;

	public UserInfo() {
	}
	
	public UserInfo(User user) {
		mUserId = user.getId();
	}
	
	public UserInfo(UserInfo userInfo) {
		mUserId = userInfo.mUserId;
		mLocation = userInfo.mLocation;
	}
	
	public UserInfo(Parcel parcel) {
		mUserId = parcel.readString();
		mLocation = parcel.readString();
	}
	
	public String getUserId() {
		return mUserId;
	}

	public String getLocation() {
		return mLocation;
	}

	public void setLocation(String location) {
		mLocation = location;
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(mUserId);
		dest.writeString(mLocation);
	}
	
	public static final Parcelable.Creator<UserInfo> CREATOR = new Parcelable.Creator<UserInfo>() {
		public UserInfo createFromParcel(Parcel in) {
			return new UserInfo(in);
		}

		public UserInfo[] newArray(int size) {
			return new UserInfo[size];
		}
	};
}
 public class UserNotFoundException extends ServiceException {

	private static final long serialVersionUID = -2452895792705200301L;

	private static final String MESSAGE_FORMAT = "User with name %s not found";

	public UserNotFoundException(String userName) {
		super(String.format(MESSAGE_FORMAT, userName));
	}

	public UserNotFoundException(String userName, Throwable throwable) {
		super(String.format(MESSAGE_FORMAT, userName), throwable);
	}

} public class PhotoDAO {

	private static final String[] SELECT_PROJECTION = new String[] {
			PhotoUrlList.Columns._ID, // 0
			PhotoUrlList.Columns.URL, // 1
			PhotoUrlList.Columns.SOURCE_TYPE, // 2
			PhotoUrlList.Columns.PHOTO_ID };

	private Context context;

	public PhotoDAO(Context context) {
		this.context = context;
	}

	public void insert(Photo photo) {
		ContentValues values = new ContentValues();
		values.put(PhotoUrlList.Columns.URL, photo.getUrlPattern());
		values.put(PhotoUrlList.Columns.SOURCE_TYPE, photo.getSourceType()
				.getValue());
		values.put(PhotoUrlList.Columns.PHOTO_ID, photo.getPhotoId());
		context.getContentResolver().insert(PhotoUrlList.CONTENT_URI, values);
	}

	public boolean hasExist(Photo photo) {
		return selectByPhotoId(photo.getPhotoId()) != null;
	}

	public Photo selectByPhotoId(String photoId) {
		Photo photo = null;
		Cursor cursor = context.getContentResolver().query(
				PhotoUrlList.CONTENT_URI, SELECT_PROJECTION, "(photo_id = ?)",
				new String[] { photoId }, null);

		boolean move = cursor.moveToFirst();
		if (move) {
			photo = new Photo();
			photo.setId(cursor.getInt(0));
			photo.setUrlPattern(cursor.getString(1));
			photo.setSourceType(SourceType.valueOf(cursor.getString(2)));
			photo.setPhotoId(cursor.getString(3));
			move = cursor.moveToNext();
		}
		cursor.close();
		return photo;
	}

	public int getTotalCount() {
		String sql = String.format("SELECT COUNT(*) FROM %s",
				PhotoUrlList.TABLE_NAME);

		SQLiteDatabase database = PhotoUrlListProvider.getReadableDatabase();
		Cursor cursor = database.rawQuery(sql, null);
		boolean move = cursor.moveToFirst();
		int totalCount = 0;
		if (move) {
			totalCount = cursor.getInt(0);
			move = cursor.moveToNext();
		}
		cursor.close();
		return totalCount;
	}

	public List<Photo> select(int start, int perPage) {
		String sql = String.format("SELECT %s,%s,%s,%s FROM %s LIMIT %s,%s",
				PhotoUrlList.Columns._ID, PhotoUrlList.Columns.URL,
				PhotoUrlList.Columns.SOURCE_TYPE,
				PhotoUrlList.Columns.PHOTO_ID, PhotoUrlList.TABLE_NAME, start,
				perPage);

		SQLiteDatabase database = PhotoUrlListProvider.getReadableDatabase();
		Cursor cursor = database.rawQuery(sql, null);

		List<Photo> dataList = new ArrayList<Photo>();
		boolean move = cursor.moveToFirst();
		while (move) {
			Photo photo = new Photo();
			photo.setId(cursor.getInt(0));
			photo.setUrlPattern(cursor.getString(1));
			photo.setSourceType(SourceType.valueOf(cursor.getString(2)));
			photo.setPhotoId(cursor.getString(3));
			dataList.add(photo);
			move = cursor.moveToNext();
		}
		cursor.close();
		return dataList;
	}

	public List<Photo> selectAll() {
		Cursor cursor = context.getContentResolver().query(
				PhotoUrlList.CONTENT_URI, SELECT_PROJECTION, null, null, null);

		List<Photo> dataList = new ArrayList<Photo>();
		boolean move = cursor.moveToFirst();
		while (move) {
			Photo photo = new Photo();
			photo.setId(cursor.getInt(0));
			photo.setUrlPattern(cursor.getString(1));
			photo.setSourceType(SourceType.valueOf(cursor.getString(2)));
			photo.setPhotoId(cursor.getString(3));
			dataList.add(photo);
			move = cursor.moveToNext();
		}
		cursor.close();
		return dataList;
	}

	public void delete(Photo photo) {
		SQLiteDatabase database = PhotoUrlListProvider.getReadableDatabase();
		database.delete(PhotoUrlList.TABLE_NAME, PhotoUrlList.Columns.PHOTO_ID
				+ "=" + photo.getPhotoId(), null);
	}

//	public void delete(long id) {
//		context.getContentResolver().delete(PhotoUrlList.CONTENT_URI,
//				PhotoUrlList.Columns._ID + "=?", new String[] { id + "" });
//	}
}
 public class UserPreferences {
	static final String NAME = "user-settings";

	public static final String NETWORK_ENABLED_KEY = "photostream.enable-network";
	public static final String NETWORK_NAME_KEY = "photostream.networkName";

	public static final String NETWORK_USER_NAME_KEY = "photostream.networkUsername";
	// public static final String NETWORK_PASSWORD_KEY =
	// "photostream.networkPassword";

	public static final String ROTATION_ENABLED_KEY = "photostream.enable-rotation";

	public static final String ROTATION_SCHEDULE_KEY = "photostream.rotation-schedule";
	public static final String ROTATION_SOURCE_KEY = "photostream.rotation_background_source";
	public static final String ROTATION_NOTIFICATION_KEY = "photostream.rotation_background_notification";
	public static final String ROTATION_MY_TAGS_KEY = "photostream.my_tags";

	public static final String EFFECTS_KEY = "photostream.effects";
	public static final String GROUP_NAME_KEY = "photostream.groupName";

	public static final String IMAGES_PER_REQUEST = "photostream.images_per_request";
	public static final String CROP_WALLPAPER = "photostream.enable-crop";
	public static final String WALLPAPER_SETTING_MODE = "photostream.wallpaper-setting-mode";

	private Context context;
	SharedPreferences preferences;

	public UserPreferences(Context context) {
		this.context = context;
		preferences = this.context.getSharedPreferences(NAME,
				Context.MODE_PRIVATE);
	}

	public boolean isNetworkEnabled() {
		return preferences.getBoolean(NETWORK_ENABLED_KEY, false);
	}

	// public String getPassword() {
	// return preferences.getString(NETWORK_PASSWORD_KEY, "");
	// }

	public String getUserName() {
		return preferences.getString(NETWORK_USER_NAME_KEY, "");
	}

	public Network getNetwork() {
		return Network.valueOf(preferences
				.getString(NETWORK_NAME_KEY, "flickr"));
	}

	public boolean isRotationEnabed() {
		return preferences.getBoolean(ROTATION_ENABLED_KEY, false);
	}

	public long getRotationSchedule() {
		return Long
				.parseLong(preferences.getString(ROTATION_SCHEDULE_KEY, "0"));
	}

	public BackgroundSource getRotationBackgroundSource() {
		return BackgroundSource.valueOf(preferences.getString(
				ROTATION_SOURCE_KEY, ""));
	}

	public boolean isRotationNotificationEnabled() {
		return preferences.getBoolean(ROTATION_NOTIFICATION_KEY, false);
	}

	public TypeEffect getTypeEffect() {
		return TypeEffect.valueOf(preferences.getString(EFFECTS_KEY, "random"));
	}

	public int getImagesPerRequest() {
		return Integer.parseInt(preferences.getString(IMAGES_PER_REQUEST, "6"));
	}

	public void registerOnSharedPreferenceChangeListener(
			OnSharedPreferenceChangeListener listener) {
		preferences.registerOnSharedPreferenceChangeListener(listener);
	}

	public void unregisterOnSharedPreferenceChangeListener(
			OnSharedPreferenceChangeListener listener) {
		preferences.unregisterOnSharedPreferenceChangeListener(listener);
	}

	public String getEmail() {
		return "22dsse@gmail.com";
	}

	public String getGroup() {
		return preferences.getString(GROUP_NAME_KEY, "344828@N24");
	}

	public String getMyTags() {
		return preferences.getString(ROTATION_MY_TAGS_KEY, "");
	}

	public boolean isCropWallpaper() {
		return preferences.getBoolean(CROP_WALLPAPER, false);
	}

	public String getWallpaperSettingMode() {
		return preferences.getString(WALLPAPER_SETTING_MODE,
				WallpaperSettingMode.ORIGINAL_MODE.getName());
	}
} public class UserSettingsActivity extends PreferenceActivity {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		getPreferenceManager().setSharedPreferencesName(UserPreferences.NAME);

		addPreferencesFromResource(R.xml.user_preferences);

		EditTextPreference networkUserName = (EditTextPreference) findPreference(UserPreferences.NETWORK_USER_NAME_KEY);

		initRotationSourcesList(networkUserName.getText());

		//final OnPreferenceChangeListener networkUserNameListener = networkUserName
				//.getOnPreferenceChangeListener();
		networkUserName
				.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

					@Override
					public boolean onPreferenceChange(Preference preference,
							Object value) {
						String text = (String) value;
						initRotationSourcesList(text);
						return true;
					}
				});
	}

	private void initRotationSourcesList(String networkName) {
		ListPreference rotationSourcePreference = (ListPreference) findPreference(UserPreferences.ROTATION_SOURCE_KEY);
		if (networkName == null || networkName.trim() == "") {

			rotationSourcePreference
					.setEntries(R.array.photo_source_type_safe_names);
			rotationSourcePreference
					.setEntryValues(R.array.photo_source_type_safe_values);
		} else {
			rotationSourcePreference
					.setEntries(R.array.photo_source_type_names);
			rotationSourcePreference
					.setEntryValues(R.array.photo_source_type_values);
		}
	}

	@Override
	protected void onStart() {
		super.onStart();
		StatisticUtils.onStartSession(this);
	}

	@Override
	protected void onStop() {
		super.onStop();
		StatisticUtils.onEndSession();
	}

	/**
	 * Starts the PreferencesActivity for the specified user.
	 * 
	 * @param context
	 *            The application's environment.
	 */
	static void show(Context context) {
		final Intent intent = new Intent(context, UserSettingsActivity.class);
		context.startActivity(intent);
	}
} public class ConfigurationReader {
	private Activity activity;

	public ConfigurationReader(Activity activity) {
		super();
		this.activity = activity;
	}

	public Configuration getConfiguration() {
		Configuration config = activity.getResources().getConfiguration();
		return config;
	}

} public class StatisticUtils {
	public static void onStartSession(Context context) {
		FlurryAgent.onStartSession(context, ActivityConstants.FLURRY_KEY);
	}

	public static void onEndSession() {
		FlurryAgent.onEndSession();
	}

} public class StreamUtils {
	private static final String TAG = "StreamUtils";

	private static final int IO_BUFFER_SIZE = 1024 * 8;

	/**
	 * Copy the content of the input stream into the output stream, using a
	 * temporary byte array buffer whose size is defined by
	 * {@link #IO_BUFFER_SIZE}.
	 * 
	 * @param in
	 *            The input stream to copy from.
	 * @param out
	 *            The output stream to copy to.
	 * 
	 * @throws IOException
	 *             If any error occurs during the copy.
	 */
	public static void copy(InputStream in, OutputStream out)
			throws IOException {
		byte[] b = new byte[IO_BUFFER_SIZE];
		int read;
		while ((read = in.read(b)) != -1) {
			out.write(b, 0, read);
		}
	}

	/**
	 * Closes the specified stream.
	 * 
	 * @param stream
	 *            The stream to close.
	 */
	public static void closeStream(Closeable stream) {
		if (stream != null) {
			try {
				stream.close();
			} catch (IOException e) {
				android.util.Log.e(TAG, "Could not close stream", e);
			}
		}
	}

	// TODO: refactore
	public static boolean saveBitmap(Context context, Bitmap bitmap,
			String filePath) {
		boolean result = false;
		try {
			FileOutputStream fos = context.openFileOutput(filePath,
					Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);

			bitmap.compress(CompressFormat.JPEG, 100, fos);

			fos.flush();
			fos.close();
			result = true;
		} catch (Exception e) {
			Log.e(TAG, e.toString());
		}
		return result;
	}
}
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewAnimator;
import com.koonen.photostream.CropWallpaperTask.CropWallpaperExecutor;
import com.koonen.photostream.api.FilePhoto;
import com.koonen.photostream.api.Photo;
import com.koonen.photostream.api.PhotoList;
import com.koonen.photostream.api.PhotoSize;
import com.koonen.photostream.api.ServiceContext;
import com.koonen.photostream.api.ServiceManager;
import com.koonen.photostream.api.ServiceNetworkException;
import com.koonen.photostream.api.UserInfo;
import com.koonen.photostream.api.UserNotFoundException;
import com.koonen.photostream.dao.PhotoDAO;
import com.koonen.photostream.settings.UserPreferences;
import com.koonen.photostream.settings.UserSettingsActivity;
import com.koonen.utils.ConfigurationReader;
import com.koonen.utils.StatisticUtils;
import com.koonen.utils.StreamUtils;
/*
 * Copyright (C) 2008 Google Inc.
 *
 * 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.koonen.photostream;



/**
 * Activity that displays a photo along with its title and the date at which it
 * was taken. This activity also lets the user set the photo as the wallpaper.
 */
public class ViewPhotoActivity extends Activity implements
		View.OnClickListener, ViewTreeObserver.OnGlobalLayoutListener,
		Animation.AnimationListener {

	// private static final String TAG = "ViewPhotoActivity";

	static final String ACTION = "com.google.android.photostream.FLICKR_PHOTO";
	static final String EXTRA_SEARCH_TAGS = "com.koonen.photostream.SearchTags";

	static final int SIMILAR_RESPONSE_ID = 1;

	static final int VIEW_PHOTO_REQUEST_ID = 1;
	static final int PREVIEW_PHOTO_REQUEST_ID = 2;

	static final int VIEW_PHOTO_SHARE_ID = 2;

	private static final String EXTRA_PHOTO = "com.koonen.photostream.photo";

	private static final String EXTRA_SERVICE_CONTEXT = "com.koonen.photostream.service_context";

	// private static final int DIALOG_SHARE = 1;
	// private static final int DIALOG_SHARE_ERROR = 2;

	private static final String STATE_SHOW_REFRESH = "show_refresh";
	private static final String STATE_PHOTO = "photo";

	public static final int REQUEST_SENT_EMAIL = 43;

	private static final String TAG = "ViewPhotoActivity";

	private Photo mPhoto;
	private ServiceContext serviceContext;
	private boolean isFirstOpen;
	private Bitmap notScaledBitmap;
	private Bitmap mBitmap;
	private boolean restoreBitmap;
	private boolean loading = false;

	private ViewAnimator mSwitcher;
	private ImageView mPhotoView;
	private ViewGroup mContainer;
	private Handler handler;
	private ImageView refreshImage;

	private View mMenuMore;
	private View mMenuNext;
	private View mMenuPrev;
	private View mMenuSeparator;

	private UserTask<?, ?, ?> mTask;
	private TextView mPhotoTags;
	private TextView mPhotoLocation;
	private TextView mPhotoDate;

	private LayoutAnimationController mNextAnimation;
	private LayoutAnimationController mBackAnimation;

	private PhotoDAO photoDAO;
	private UserPreferences userPreferences;

	private boolean photoExist = false;
	private static final String STATE_CONTEXT = "requeset_context";

	private int currentOrientation;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		photoDAO = new PhotoDAO(this);
		userPreferences = new UserPreferences(this);
		handler = new Handler();

		mPhoto = getPhoto();
		serviceContext = getServiceContext();
		isFirstOpen = true;

		// mBitmap = null;
		restoreBitmap = false;

		Configuration config = new ConfigurationReader(this).getConfiguration();
		currentOrientation = config.orientation;
		initActivity();
	}

	@Override
	protected void onStart() {
		super.onStart();
		StatisticUtils.onStartSession(this);
	}

	@Override
	protected void onStop() {
		super.onStop();
		StatisticUtils.onEndSession();
	}

	private void initActivity() {
		if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
			setContentView(R.layout.screen_photo);
		} else {
			setContentView(R.layout.screen_photo_landscape);
		}
		setupViews();
	}

	/**
	 * Starts the ViewPhotoActivity for the specified photo.
	 * 
	 * @param context
	 *            The application's environment.
	 * @param photo
	 *            The photo to display and optionally set as a wallpaper.
	 */
	static void show(Activity context, Photo photo,
			ServiceContext serviceContext, int photoPageNumber) {
		ServiceContext singleServiceContext = ServiceContext
				.createSingleContext(serviceContext, photoPageNumber);
		final Intent intent = new Intent(context, ViewPhotoActivity.class);

		intent.putExtra(EXTRA_PHOTO, photo);
		intent.putExtra(EXTRA_SERVICE_CONTEXT, singleServiceContext);
		context.startActivityForResult(intent, VIEW_PHOTO_REQUEST_ID);
	}

	static void show(Activity context, FilePhoto photo) {