summaryrefslogtreecommitdiffstats
path: root/photoviewer
diff options
context:
space:
mode:
authorAndrew Sapperstein <asapperstein@google.com>2012-08-03 13:44:57 -0700
committerAndrew Sapperstein <asapperstein@google.com>2012-08-03 14:41:50 -0700
commit509bd03a2a783f804e9456767b52e0f8ef43479b (patch)
tree47952020b5f9e0b5a2a7d71e4c935c09bb4f23dd /photoviewer
parentb81f8c963a0d97034872f14f4e2294d1e2b44da1 (diff)
downloadandroid_frameworks_ex-509bd03a2a783f804e9456767b52e0f8ef43479b.tar.gz
android_frameworks_ex-509bd03a2a783f804e9456767b52e0f8ef43479b.tar.bz2
android_frameworks_ex-509bd03a2a783f804e9456767b52e0f8ef43479b.zip
Enabled optional support for showing progress.
Added some progress bars to the "empty" view so that implementors of the API can show the progress of things like downloads or loading. Additionally, added a retry button and an optional text that allows you to indicate status to the user. Due to a bug in the framework, we actually use two progress bars (one determinate and one indeterminate) to update our status. Created a wrapper that allows the controlling of both progress bars in sync. Change-Id: I710e06317948d376d445abf1603545982ac8479d
Diffstat (limited to 'photoviewer')
-rw-r--r--photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.pngbin0 -> 1330 bytes
-rw-r--r--photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.pngbin0 -> 889 bytes
-rw-r--r--photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.pngbin0 -> 1765 bytes
-rw-r--r--photoviewer/res/layout/photo_fragment_view.xml58
-rw-r--r--photoviewer/res/values/dimen.xml6
-rw-r--r--photoviewer/res/values/strings.xml11
-rw-r--r--photoviewer/src/com/android/ex/photo/PhotoViewActivity.java42
-rw-r--r--photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java72
-rw-r--r--photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java68
9 files changed, 200 insertions, 57 deletions
diff --git a/photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.png b/photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.png
new file mode 100644
index 0000000..69ac31b
--- /dev/null
+++ b/photoviewer/res/drawable-hdpi/ic_menu_refresh_holo_dark.png
Binary files differ
diff --git a/photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.png b/photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.png
new file mode 100644
index 0000000..f68aacf
--- /dev/null
+++ b/photoviewer/res/drawable-mdpi/ic_menu_refresh_holo_dark.png
Binary files differ
diff --git a/photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.png b/photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.png
new file mode 100644
index 0000000..3db90ee
--- /dev/null
+++ b/photoviewer/res/drawable-xhdpi/ic_menu_refresh_holo_dark.png
Binary files differ
diff --git a/photoviewer/res/layout/photo_fragment_view.xml b/photoviewer/res/layout/photo_fragment_view.xml
index 9430d1b..3dea9f1 100644
--- a/photoviewer/res/layout/photo_fragment_view.xml
+++ b/photoviewer/res/layout/photo_fragment_view.xml
@@ -24,11 +24,59 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <FrameLayout
+ android:id="@+id/photo_preview"
+ android:layout_width="@dimen/photo_preview_size"
+ android:layout_height="@dimen/photo_preview_size"
+ android:layout_centerInParent="true" >
+
+ <ImageView
+ android:id="@+id/photo_preview_image"
+ android:layout_width="@dimen/photo_preview_size"
+ android:layout_height="@dimen/photo_preview_size"
+ android:layout_gravity="center"
+ android:scaleType="centerCrop"
+ android:src="@drawable/default_image"
+ android:visibility="gone" />
+
+ <ProgressBar
+ android:id="@+id/indeterminate_progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="@dimen/photo_preview_size"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:indeterminate="true"
+ android:visibility="gone" />
+
+ <ProgressBar
+ android:id="@+id/determinate_progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="@dimen/photo_preview_size"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:indeterminate="false"
+ android:visibility="gone" />
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/empty_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/photo_preview"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="8dip"
+ android:textColor="@android:color/white"
+ android:visibility="gone" />
+
<ImageView
- android:id="@+id/photo_preview_image"
- android:layout_width="256dip"
- android:layout_height="256dip"
- android:layout_centerInParent="true"
- />
+ android:id="@+id/retry_button"
+ android:layout_width="@dimen/retry_button_size"
+ android:layout_height="@dimen/retry_button_size"
+ android:layout_below="@id/empty_text"
+ android:layout_centerHorizontal="true"
+ android:background="?android:attr/selectableItemBackground"
+ android:scaleType="center"
+ android:src="@drawable/ic_menu_refresh_holo_dark"
+ android:visibility="gone" />
</RelativeLayout>
diff --git a/photoviewer/res/values/dimen.xml b/photoviewer/res/values/dimen.xml
index bb4aa90..c1b8b90 100644
--- a/photoviewer/res/values/dimen.xml
+++ b/photoviewer/res/values/dimen.xml
@@ -17,6 +17,8 @@
-->
<resources>
- <dimen name="photo_crop_width">280dp</dimen>
- <dimen name="photo_crop_stroke_width">1dp</dimen>
+ <dimen name="photo_crop_width">280dip</dimen>
+ <dimen name="photo_crop_stroke_width">1dip</dimen>
+ <dimen name="photo_preview_size">200dip</dimen>
+ <dimen name="retry_button_size">48dip</dimen>
</resources>
diff --git a/photoviewer/res/values/strings.xml b/photoviewer/res/values/strings.xml
index fe37745..b635122 100644
--- a/photoviewer/res/values/strings.xml
+++ b/photoviewer/res/values/strings.xml
@@ -16,16 +16,7 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Default title for photo view [CHAR LIMIT=40] -->
- <string name="photo_view_default_title">Photos from message</string>
- <!-- Toast message if there was a problem loading the photo view. [CHAR LIMIT=80] -->
- <string name="photo_view_load_error">Photo couldn\'t be loaded.</string>
- <!-- Message displayed when trying to play a video that isn't ready [CHAR LIMIT=100] -->
- <string name="photo_view_video_not_ready">Video not available at this time. Please refresh.</string>
- <!-- Displayed in a toast if the photo taken from the camera was not found. -->
- <string name="camera_photo_error">Can\'t find photo.</string>
<!-- Photo view sub-title for current photo position [CHAR LIMIT=10] -->
<string name="photo_view_count"><xliff:g id="current_pos">%d</xliff:g> of <xliff:g id="count">%d</xliff:g></string>
- <!-- Status message displayed while a list's content is loading -->
- <string name="loading_photo">Loading&#8230;</string>
+ <string name="retry">Retry</string>
</resources> \ No newline at end of file
diff --git a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java b/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java
index 170a9eb..aa8029e 100644
--- a/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java
+++ b/photoviewer/src/com/android/ex/photo/PhotoViewActivity.java
@@ -18,6 +18,7 @@
package com.android.ex.photo;
import android.app.ActionBar;
+import android.app.ActionBar.OnMenuVisibilityListener;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Fragment;
@@ -48,7 +49,7 @@ import java.util.Set;
*/
public class PhotoViewActivity extends Activity implements
LoaderCallbacks<Cursor>, OnPageChangeListener, OnInterceptTouchListener,
- OnFragmentPagerListener {
+ OnFragmentPagerListener, OnMenuVisibilityListener {
/**
* Listener to be invoked for screen events.
@@ -205,6 +206,8 @@ public class PhotoViewActivity extends Activity implements
actionBar.setDisplayHomeAsUpEnabled(true);
mActionBarHideDelayTime = getResources().getInteger(
R.integer.action_bar_delay_time_in_millis);
+ actionBar.addOnMenuVisibilityListener(this);
+ mActionBarHideHandler = new Handler();
}
@Override
@@ -328,7 +331,7 @@ public class PhotoViewActivity extends Activity implements
notifyCursorListeners(data);
mViewPager.setCurrentItem(itemIndex, false);
- updateActionBar();
+ setViewActivated();
}
});
}
@@ -353,9 +356,8 @@ public class PhotoViewActivity extends Activity implements
@Override
public void onPageSelected(int position) {
- setViewActivated();
- updateActionBar();
mPhotoIndex = position;
+ setViewActivated();
}
@Override
@@ -375,6 +377,7 @@ public class PhotoViewActivity extends Activity implements
}
public void onFragmentVisible(PhotoViewFragment fragment) {
+ updateActionBar(fragment);
}
@Override
@@ -412,18 +415,11 @@ public class PhotoViewActivity extends Activity implements
if (mFullScreen) {
setLightsOutMode(true);
- if (mActionBarHideHandler == null) {
- mActionBarHideHandler = new Handler();
- }
- mActionBarHideHandler.removeCallbacks(mActionBarHideRunnable);
+ cancelActionBarHideRunnable();
} else {
setLightsOutMode(false);
if (setDelayedRunnable) {
- if (mActionBarHideHandler == null) {
- mActionBarHideHandler = new Handler();
- }
- mActionBarHideHandler.postDelayed(mActionBarHideRunnable,
- mActionBarHideDelayTime);
+ postActionBarHideRunnableWithDelay();
}
}
@@ -434,6 +430,15 @@ public class PhotoViewActivity extends Activity implements
}
}
+ private void postActionBarHideRunnableWithDelay() {
+ mActionBarHideHandler.postDelayed(mActionBarHideRunnable,
+ mActionBarHideDelayTime);
+ }
+
+ private void cancelActionBarHideRunnable() {
+ mActionBarHideHandler.removeCallbacks(mActionBarHideRunnable);
+ }
+
private void setLightsOutMode(boolean enabled) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
int flags = enabled
@@ -476,7 +481,7 @@ public class PhotoViewActivity extends Activity implements
/**
* Adjusts the activity title and subtitle to reflect the photo name and count.
*/
- protected void updateActionBar() {
+ protected void updateActionBar(PhotoViewFragment fragment) {
final int position = mViewPager.getCurrentItem() + 1;
final String subtitle;
final boolean hasAlbumCount = mAlbumCount >= 0;
@@ -526,4 +531,13 @@ public class PhotoViewActivity extends Activity implements
public Cursor getCursor() {
return (mAdapter == null) ? null : mAdapter.getCursor();
}
+
+ @Override
+ public void onMenuVisibilityChanged(boolean isVisible) {
+ if (isVisible) {
+ cancelActionBarHideRunnable();
+ } else {
+ postActionBarHideRunnableWithDelay();
+ }
+ }
}
diff --git a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java
index 8479f2c..b8bfd4f 100644
--- a/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java
+++ b/photoviewer/src/com/android/ex/photo/fragments/PhotoViewFragment.java
@@ -19,6 +19,7 @@ package com.android.ex.photo.fragments;
import android.app.Activity;
import android.app.Fragment;
+import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context;
import android.content.Intent;
@@ -26,7 +27,6 @@ import android.content.Loader;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Bundle;
-import android.app.LoaderManager;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
@@ -34,6 +34,8 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
import com.android.ex.photo.Intents;
import com.android.ex.photo.PhotoViewActivity;
@@ -44,6 +46,7 @@ import com.android.ex.photo.adapters.PhotoPagerAdapter;
import com.android.ex.photo.loaders.PhotoBitmapLoader;
import com.android.ex.photo.util.ImageUtils;
import com.android.ex.photo.views.PhotoView;
+import com.android.ex.photo.views.ProgressBarWrapper;
/**
* Displays a photo.
@@ -93,13 +96,17 @@ public class PhotoViewFragment extends Fragment implements
private PhotoPagerAdapter mAdapter;
private PhotoView mPhotoView;
- private ImageView mPhotoPreview;
+ private ImageView mPhotoPreviewImage;
+ private TextView mEmptyText;
+ private ImageView mRetryButton;
+ private ProgressBarWrapper mPhotoProgressBar;
+
private final int mPosition;
/** Whether or not the fragment should make the photo full-screen */
private boolean mFullScreen;
- private boolean mShowingThumbnail;
+ private View mPhotoPreviewAndProgress;
public PhotoViewFragment() {
mPosition = -1;
@@ -109,7 +116,6 @@ public class PhotoViewFragment extends Fragment implements
mIntent = intent;
mPosition = position;
mAdapter = adapter;
- mShowingThumbnail = false;
}
@Override
@@ -117,7 +123,8 @@ public class PhotoViewFragment extends Fragment implements
super.onAttach(activity);
mCallback = (PhotoViewActivity) activity;
if (mCallback == null) {
- throw new IllegalArgumentException("Activity must be a derived class of PhotoViewActivity");
+ throw new IllegalArgumentException(
+ "Activity must be a derived class of PhotoViewActivity");
}
if (sPhotoSize == null) {
@@ -171,7 +178,15 @@ public class PhotoViewFragment extends Fragment implements
mPhotoView.setFullScreen(mFullScreen, false);
mPhotoView.enableImageTransforms(true);
- mPhotoPreview = (ImageView) view.findViewById(R.id.photo_preview_image);
+ mPhotoPreviewAndProgress = view.findViewById(R.id.photo_preview);
+ mPhotoPreviewImage = (ImageView) view.findViewById(R.id.photo_preview_image);
+ final ProgressBar indeterminate =
+ (ProgressBar) view.findViewById(R.id.indeterminate_progress);
+ final ProgressBar determinate =
+ (ProgressBar) view.findViewById(R.id.determinate_progress);
+ mPhotoProgressBar = new ProgressBarWrapper(determinate, indeterminate, true);
+ mEmptyText = (TextView) view.findViewById(R.id.empty_text);
+ mRetryButton = (ImageView) view.findViewById(R.id.retry_button);
// Don't call until we've setup the entire view
setViewVisibility();
@@ -242,36 +257,29 @@ public class PhotoViewFragment extends Fragment implements
case LOADER_ID_PHOTO:
if (data == null) {
getLoaderManager().initLoader(LOADER_ID_THUMBNAIL, null, this);
- return;
+ } else {
+ bindPhoto(data);
+ mPhotoPreviewAndProgress.setVisibility(View.GONE);
}
-
- mShowingThumbnail = false;
- bindPhoto(data);
- mCallback.setViewActivated();
- setViewVisibility();
- mPhotoPreview.setVisibility(View.GONE);
break;
case LOADER_ID_THUMBNAIL:
if (isPhotoBound()) {
return;
- }
-
- if (data == null) {
+ } else if (data == null) {
// no preview, show default
- mPhotoPreview.setVisibility(View.VISIBLE);
- mPhotoPreview.setImageResource(R.drawable.default_image);
- return;
+ mPhotoPreviewImage.setVisibility(View.VISIBLE);
+ mPhotoPreviewImage.setImageResource(R.drawable.default_image);
+ } else {
+ mPhotoPreviewImage.setVisibility(View.VISIBLE);
+ mPhotoPreviewImage.setImageBitmap(data);
}
-
- mShowingThumbnail = true;
- mPhotoPreview.setVisibility(View.VISIBLE);
- mPhotoPreview.setImageBitmap(data);
- mCallback.setViewActivated();
- setViewVisibility();
break;
default:
break;
}
+
+ mCallback.setViewActivated();
+ setViewVisibility();
}
/**
@@ -350,7 +358,7 @@ public class PhotoViewFragment extends Fragment implements
* Returns {@code true} if a photo has been bound. Otherwise, returns {@code false}.
*/
public boolean isPhotoBound() {
- return (mPhotoView != null && mPhotoView.isPhotoBound() && !mShowingThumbnail);
+ return (mPhotoView != null && mPhotoView.isPhotoBound());
}
/**
@@ -386,4 +394,16 @@ public class PhotoViewFragment extends Fragment implements
loader.forceLoad();
}
}
+
+ public ProgressBarWrapper getPhotoProgressBar() {
+ return mPhotoProgressBar;
+ }
+
+ public TextView getEmptyText() {
+ return mEmptyText;
+ }
+
+ public ImageView getRetryButton() {
+ return mRetryButton;
+ }
}
diff --git a/photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java b/photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java
new file mode 100644
index 0000000..77b9000
--- /dev/null
+++ b/photoviewer/src/com/android/ex/photo/views/ProgressBarWrapper.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ex.photo.views;
+
+import android.view.View;
+import android.widget.ProgressBar;
+
+/**
+ * This class wraps around two progress bars and is solely designed to fix
+ * a bug in the framework (b/6928449) that prevents a progress bar from
+ * gracefully switching back and forth between indeterminate and determinate
+ * modes.
+ */
+public class ProgressBarWrapper {
+ private ProgressBar mDeterminate;
+ private ProgressBar mIndeterminate;
+ private boolean mIsIndeterminate;
+
+ public ProgressBarWrapper(ProgressBar determinate,
+ ProgressBar indeterminate, boolean isIndeterminate) {
+ mDeterminate = determinate;
+ mIndeterminate = indeterminate;
+ setIndeterminate(isIndeterminate);
+ }
+
+ public void setIndeterminate(boolean isIndeterminate) {
+ mIsIndeterminate = isIndeterminate;
+
+ setVisibility(mIsIndeterminate);
+ }
+
+ public void setVisibility(int visibility) {
+ if (visibility == View.INVISIBLE || visibility == View.GONE) {
+ mIndeterminate.setVisibility(visibility);
+ mDeterminate.setVisibility(visibility);
+ } else {
+ setVisibility(mIsIndeterminate);
+ }
+ }
+
+ private void setVisibility(boolean isIndeterminate) {
+ mIndeterminate.setVisibility(isIndeterminate ? View.VISIBLE : View.GONE);
+ mDeterminate.setVisibility(isIndeterminate ? View.GONE : View.VISIBLE);
+ }
+
+ public void setMax(int max) {
+ mDeterminate.setMax(max);
+ }
+
+ public void setProgress(int progress) {
+ mDeterminate.setProgress(progress);
+ }
+}