1/* 2 * Copyright (C) 2011 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.ex.photo; 19 20import android.app.Activity; 21import android.content.ContentProvider; 22import android.content.Context; 23import android.content.Intent; 24import android.net.Uri; 25 26import com.android.ex.photo.fragments.PhotoViewFragment; 27 28/** 29 * Build intents to start app activities 30 */ 31 32public class Intents { 33 // Intent extras 34 public static final String EXTRA_PHOTO_INDEX = "photo_index"; 35 public static final String EXTRA_INITIAL_PHOTO_URI = "initial_photo_uri"; 36 public static final String EXTRA_PHOTOS_URI = "photos_uri"; 37 public static final String EXTRA_RESOLVED_PHOTO_URI = "resolved_photo_uri"; 38 public static final String EXTRA_PROJECTION = "projection"; 39 public static final String EXTRA_THUMBNAIL_URI = "thumbnail_uri"; 40 public static final String EXTRA_MAX_INITIAL_SCALE = "max_scale"; 41 public static final String EXTRA_WATCH_NETWORK = "watch_network"; 42 public static final String EXTRA_ENABLE_TIMER_LIGHTS_OUT = "enable_timer_lights_out"; 43 44 45 // Parameters affecting the intro/exit animation 46 public static final String EXTRA_SCALE_UP_ANIMATION = "scale_up_animation"; 47 public static final String EXTRA_ANIMATION_START_X = "start_x_extra"; 48 public static final String EXTRA_ANIMATION_START_Y = "start_y_extra"; 49 public static final String EXTRA_ANIMATION_START_WIDTH = "start_width_extra"; 50 public static final String EXTRA_ANIMATION_START_HEIGHT = "start_height_extra"; 51 52 // Parameters affecting the display and features 53 public static final String EXTRA_ACTION_BAR_HIDDEN_INITIALLY = "action_bar_hidden_initially"; 54 public static final String EXTRA_DISPLAY_THUMBS_FULLSCREEN = "display_thumbs_fullscreen"; 55 56 /** 57 * Gets a photo view intent builder to display the photos from phone activity. 58 * 59 * @param context The context 60 * @return The intent builder 61 */ 62 public static PhotoViewIntentBuilder newPhotoViewActivityIntentBuilder(Context context) { 63 return new PhotoViewIntentBuilder(context, PhotoViewActivity.class); 64 } 65 66 /** 67 * Gets a photo view intent builder to display the photo view fragment 68 * 69 * @param context The context 70 * @return The intent builder 71 */ 72 public static PhotoViewIntentBuilder newPhotoViewFragmentIntentBuilder(Context context) { 73 return newPhotoViewFragmentIntentBuilder(context, PhotoViewFragment.class); 74 } 75 76 /** 77 * Gets a photo view intent builder to display the photo view fragment with a custom fragment 78 * subclass. 79 * 80 * @param context The context 81 * @param clazz Subclass of PhotoViewFragment to use 82 * @return The intent builder 83 */ 84 public static PhotoViewIntentBuilder newPhotoViewFragmentIntentBuilder(Context context, 85 Class<? extends PhotoViewFragment> clazz) { 86 return new PhotoViewIntentBuilder(context, clazz); 87 } 88 89 /** Gets a new photo view intent builder */ 90 public static PhotoViewIntentBuilder newPhotoViewIntentBuilder( 91 Context context, Class<? extends Activity> cls) { 92 return new PhotoViewIntentBuilder(context, cls); 93 } 94 95 /** Gets a new photo view intent builder */ 96 public static PhotoViewIntentBuilder newPhotoViewIntentBuilder( 97 Context context, String activityName) { 98 return new PhotoViewIntentBuilder(context, activityName); 99 } 100 101 /** Builder to create a photo view intent */ 102 public static class PhotoViewIntentBuilder { 103 private final Intent mIntent; 104 105 /** The index of the photo to show */ 106 private Integer mPhotoIndex; 107 /** The URI of the initial photo to show */ 108 private String mInitialPhotoUri; 109 /** The URI of the initial thumbnail to show */ 110 private String mInitialThumbnailUri; 111 /** The URI of the group of photos to display */ 112 private String mPhotosUri; 113 /** The URL of the photo to display */ 114 private String mResolvedPhotoUri; 115 /** The projection for the query to use; optional */ 116 private String[] mProjection; 117 /** The URI of a thumbnail of the photo to display */ 118 private String mThumbnailUri; 119 /** The maximum scale to display images at before */ 120 private Float mMaxInitialScale; 121 /** True if lights out should automatically be invoked on a timer basis */ 122 private boolean mEnableTimerLightsOut; 123 /** 124 * True if the PhotoViewFragments should watch for network changes to restart their loaders 125 */ 126 private boolean mWatchNetwork; 127 /** true we want to run the image scale animation */ 128 private boolean mScaleAnimation; 129 /** The parameters for performing the scale up/scale down animations 130 * upon enter and exit. StartX and StartY represent the screen coordinates 131 * of the upper left corner of the start rectangle, startWidth and startHeight 132 * represent the width and height of the start rectangle. 133 */ 134 private int mStartX; 135 private int mStartY; 136 private int mStartWidth; 137 private int mStartHeight; 138 139 private boolean mActionBarHiddenInitially; 140 private boolean mDisplayFullScreenThumbs; 141 142 private PhotoViewIntentBuilder(Context context, Class<?> cls) { 143 mIntent = new Intent(context, cls); 144 initialize(); 145 } 146 147 private PhotoViewIntentBuilder(Context context, String activityName) { 148 mIntent = new Intent(); 149 mIntent.setClassName(context, activityName); 150 initialize(); 151 } 152 153 private void initialize() { 154 mScaleAnimation = false; 155 mActionBarHiddenInitially = false; 156 mDisplayFullScreenThumbs = false; 157 mEnableTimerLightsOut = true; 158 } 159 160 /** Sets auto lights out */ 161 public PhotoViewIntentBuilder setEnableTimerLightsOut(boolean enable) { 162 mEnableTimerLightsOut = enable; 163 return this; 164 } 165 166 /** Sets the photo index */ 167 public PhotoViewIntentBuilder setPhotoIndex(Integer photoIndex) { 168 mPhotoIndex = photoIndex; 169 return this; 170 } 171 172 /** Sets the initial photo URI */ 173 public PhotoViewIntentBuilder setInitialPhotoUri(String initialPhotoUri) { 174 mInitialPhotoUri = initialPhotoUri; 175 return this; 176 } 177 178 /** Sets the photos URI */ 179 public PhotoViewIntentBuilder setPhotosUri(String photosUri) { 180 mPhotosUri = photosUri; 181 return this; 182 } 183 184 /** Sets the query projection */ 185 public PhotoViewIntentBuilder setProjection(String[] projection) { 186 mProjection = projection; 187 return this; 188 } 189 190 /** Sets the resolved photo URI. This method is for the case 191 * where the URI given to {@link PhotoViewActivity} points directly 192 * to a single image and does not need to be resolved via a query 193 * to the {@link ContentProvider}. If this value is set, it supersedes 194 * {@link #setPhotosUri(String)}. */ 195 public PhotoViewIntentBuilder setResolvedPhotoUri(String resolvedPhotoUri) { 196 mResolvedPhotoUri = resolvedPhotoUri; 197 return this; 198 } 199 200 /** 201 * Sets the URI for a thumbnail preview of the photo. 202 */ 203 public PhotoViewIntentBuilder setThumbnailUri(String thumbnailUri) { 204 mThumbnailUri = thumbnailUri; 205 return this; 206 } 207 208 /** 209 * Sets the maximum scale which an image is initially displayed at 210 */ 211 public PhotoViewIntentBuilder setMaxInitialScale(float maxScale) { 212 mMaxInitialScale = maxScale; 213 return this; 214 } 215 216 /** 217 * Enable watching the network for connectivity changes. 218 * 219 * When a change is detected, bitmap loaders will be restarted if required. 220 */ 221 public PhotoViewIntentBuilder watchNetworkConnectivityChanges() { 222 mWatchNetwork = true; 223 return this; 224 } 225 226 /** 227 * Enable a scale animation that animates the initial photo URI passed in using 228 * {@link #setInitialPhotoUri}. 229 * 230 * Note: To avoid janky transitions, particularly when exiting the photoviewer, ensure the 231 * following system UI flags are set on the root view of the relying app's activity 232 * (via @{link View.setSystemUiVisibility(int)}): 233 * {@code View.SYSTEM_UI_FLAG_VISIBLE | View.SYSTEM_UI_FLAG_LAYOUT_STABLE} 234 * As well, client should ensure {@code android:fitsSystemWindows} is set on the root 235 * content view. 236 */ 237 public PhotoViewIntentBuilder setScaleAnimation(int startX, int startY, 238 int startWidth, int startHeight) { 239 mScaleAnimation = true; 240 mStartX = startX; 241 mStartY = startY; 242 mStartWidth = startWidth; 243 mStartHeight = startHeight; 244 return this; 245 } 246 247 // If this option is turned on, then the photoViewer will be initially 248 // displayed with the action bar hidden. This is as opposed to the default 249 // behavior, where the actionBar is initially shown. 250 public PhotoViewIntentBuilder setActionBarHiddenInitially( 251 boolean actionBarHiddenInitially) { 252 mActionBarHiddenInitially = actionBarHiddenInitially; 253 return this; 254 } 255 256 // If this option is turned on, then the small, lo-res thumbnail will 257 // be scaled up to the maximum size to cover as much of the screen as 258 // possible while still maintaining the correct aspect ratio. This means 259 // that the image may appear blurry until the the full-res image is 260 // loaded. 261 // This is as opposed to the default behavior, where only part of the 262 // thumbnail is displayed in a small view in the center of the screen, 263 // and a loading spinner is displayed until the full-res image is loaded. 264 public PhotoViewIntentBuilder setDisplayThumbsFullScreen( 265 boolean displayFullScreenThumbs) { 266 mDisplayFullScreenThumbs = displayFullScreenThumbs; 267 return this; 268 } 269 270 /** Build the intent */ 271 public Intent build() { 272 mIntent.setAction(Intent.ACTION_VIEW); 273 274 // In Lollipop, each list of photos should appear as a document in the "Recents" 275 // list. In earlier versions, this flag was Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET. 276 mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT 277 // FLAG_ACTIVITY_CLEAR_TOP is needed for the case where the app tries to 278 // display a different photo while there is an existing activity instance 279 // for that list of photos. Since the initial photo is specified as an 280 // extra, without FLAG_ACTIVITY_CLEAR_TOP, the activity instance would 281 // just get restarted and it would display whatever photo it was last 282 // displaying. FLAG_ACTIVITY_CLEAR_TOP causes a new instance to be created, 283 // and it will display the new initial photo. 284 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 285 286 if (mPhotoIndex != null) { 287 mIntent.putExtra(EXTRA_PHOTO_INDEX, (int) mPhotoIndex); 288 } 289 290 if (mInitialPhotoUri != null) { 291 mIntent.putExtra(EXTRA_INITIAL_PHOTO_URI, mInitialPhotoUri); 292 } 293 294 if (mInitialPhotoUri != null && mPhotoIndex != null) { 295 throw new IllegalStateException( 296 "specified both photo index and photo uri"); 297 } 298 299 if (mPhotosUri != null) { 300 mIntent.putExtra(EXTRA_PHOTOS_URI, mPhotosUri); 301 mIntent.setData(Uri.parse(mPhotosUri)); 302 } 303 304 if (mResolvedPhotoUri != null) { 305 mIntent.putExtra(EXTRA_RESOLVED_PHOTO_URI, mResolvedPhotoUri); 306 } 307 308 if (mProjection != null) { 309 mIntent.putExtra(EXTRA_PROJECTION, mProjection); 310 } 311 312 if (mThumbnailUri != null) { 313 mIntent.putExtra(EXTRA_THUMBNAIL_URI, mThumbnailUri); 314 } 315 316 if (mMaxInitialScale != null) { 317 mIntent.putExtra(EXTRA_MAX_INITIAL_SCALE, mMaxInitialScale); 318 } 319 320 mIntent.putExtra(EXTRA_WATCH_NETWORK, mWatchNetwork); 321 322 mIntent.putExtra(EXTRA_SCALE_UP_ANIMATION, mScaleAnimation); 323 if (mScaleAnimation) { 324 mIntent.putExtra(EXTRA_ANIMATION_START_X, mStartX); 325 mIntent.putExtra(EXTRA_ANIMATION_START_Y, mStartY); 326 mIntent.putExtra(EXTRA_ANIMATION_START_WIDTH, mStartWidth); 327 mIntent.putExtra(EXTRA_ANIMATION_START_HEIGHT, mStartHeight); 328 } 329 330 mIntent.putExtra(EXTRA_ACTION_BAR_HIDDEN_INITIALLY, mActionBarHiddenInitially); 331 mIntent.putExtra(EXTRA_DISPLAY_THUMBS_FULLSCREEN, mDisplayFullScreenThumbs); 332 mIntent.putExtra(EXTRA_ENABLE_TIMER_LIGHTS_OUT, mEnableTimerLightsOut); 333 return mIntent; 334 } 335 } 336} 337