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