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