alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (ViewPhotoActivity.java)

This example Android source code file (ViewPhotoActivity.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

android, bitmap, boolean, could, drawing, integer, intent, io, ioexception, object, override, request_crop_image, string, textview, ui, usertask, view, viewanimator, void, widget

The ViewPhotoActivity.java Android example source code

/*
 * 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.google.android.photostream;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.ActivityNotFoundException;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.ImageView;
import android.widget.ViewAnimator;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Menu;
import android.view.MenuItem;
import android.view.animation.AnimationUtils;
import android.net.Uri;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.FileNotFoundException;

/**
 * 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 {

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

    private static final String RADAR_ACTION = "com.google.android.radar.SHOW_RADAR";
    private static final String RADAR_EXTRA_LATITUDE = "latitude";
    private static final String RADAR_EXTRA_LONGITUDE = "longitude";

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

    private static final String WALLPAPER_FILE_NAME = "wallpaper";

    private static final int REQUEST_CROP_IMAGE = 42;

    private Flickr.Photo mPhoto;

    private ViewAnimator mSwitcher;
    private ImageView mPhotoView;
    private ViewGroup mContainer;

    private UserTask<?, ?, ?> mTask;
    private TextView mPhotoTitle;
    private TextView mPhotoDate;

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

        mPhoto = getPhoto();

        setContentView(R.layout.screen_photo);
        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(Context context, Flickr.Photo photo) {
        final Intent intent = new Intent(ACTION);
        intent.putExtra(EXTRA_PHOTO, photo);
        context.startActivity(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mTask != null && mTask.getStatus() != UserTask.Status.RUNNING) {
            mTask.cancel(true);
        }
    }

    private void setupViews() {
        mContainer = (ViewGroup) findViewById(R.id.container_photo);
        mSwitcher = (ViewAnimator) findViewById(R.id.switcher_menu);
        mPhotoView = (ImageView) findViewById(R.id.image_photo);

        mPhotoTitle = (TextView) findViewById(R.id.caption_title);
        mPhotoDate = (TextView) findViewById(R.id.caption_date);

        findViewById(R.id.menu_back).setOnClickListener(this);
        findViewById(R.id.menu_set).setOnClickListener(this);

        mPhotoTitle.setText(mPhoto.getTitle());
        mPhotoDate.setText(mPhoto.getDate());

        mContainer.setVisibility(View.INVISIBLE);

        // Sets up a view tree observer. The photo will be scaled using the size
        // of one of our views so we must wait for the first layout pass to be
        // done to make sure we have the correct size.
        mContainer.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    /**
     * Loads the photo after the first layout. The photo is scaled using the
     * dimension of the ImageView that will ultimately contain the photo's
     * bitmap. We make sure that the ImageView is laid out at least once to
     * get its correct size.
     */
    public void onGlobalLayout() {
        mContainer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        loadPhoto(mPhotoView.getMeasuredWidth(), mPhotoView.getMeasuredHeight());
    }

    /**
     * Loads the photo either from the last known instance or from the network.
     * Loading it from the last known instance allows for fast display rotation
     * without having to download the photo from the network again.
     *
     * @param width The desired maximum width of the photo.
     * @param height The desired maximum height of the photo.
     */
    private void loadPhoto(int width, int height) {
        final Object data = getLastNonConfigurationInstance();
        if (data == null) {
            mTask = new LoadPhotoTask().execute(mPhoto, width, height);
        } else {
            mPhotoView.setImageBitmap((Bitmap) data);
            mSwitcher.showNext();
        }
    }

    /**
     * Loads the {@link com.google.android.photostream.Flickr.Photo} to display
     * from the intent used to start the activity.
     *
     * @return The photo to display, or null if the photo cannot be found.
     */
    public Flickr.Photo getPhoto() {
        final Intent intent = getIntent();
        final Bundle extras = intent.getExtras();

        Flickr.Photo photo = null;
        if (extras != null) {
            photo = extras.getParcelable(EXTRA_PHOTO);
        }

        return photo;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.view_photo, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_item_radar:
                onShowRadar();
                break;
        }
        return super.onMenuItemSelected(featureId, item);
    }

    private void onShowRadar() {
        new ShowRadarTask().execute(mPhoto);
    }

    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.menu_back:
                onBack();
                break;
            case R.id.menu_set:
                onSet();
                break;
        }
    }

    private void onSet() {
        mTask = new CropWallpaperTask().execute(mPhoto);
    }

    private void onBack() {
        finish();
    }

    /**
     * If we successfully loaded a photo, send it to our future self to allow
     * for fast display rotation. By doing so, we avoid reloading the photo
     * from the network when the activity is taken down and recreated upon
     * display rotation.
     *
     * @return The Bitmap displayed in the ImageView, or null if the photo
     *         wasn't loaded.
     */
    @Override
    public Object onRetainNonConfigurationInstance() {
        final Drawable d = mPhotoView.getDrawable();
        return d != null ? ((BitmapDrawable) d).getBitmap() : null;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // Spawns a new task to set the wallpaper in a background thread when/if
        // we receive a successful result from the image cropper.
        if (requestCode == REQUEST_CROP_IMAGE) {
            if (resultCode == RESULT_OK) {
                mTask = new SetWallpaperTask().execute();
            } else {
                cleanupWallpaper();
                showWallpaperError();
            }
        }
    }

    private void showWallpaperError() {
        Toast.makeText(ViewPhotoActivity.this, R.string.error_cannot_save_file,
                Toast.LENGTH_SHORT).show();
    }

    private void showWallpaperSuccess() {
        Toast.makeText(ViewPhotoActivity.this, R.string.success_wallpaper_set,
                Toast.LENGTH_SHORT).show();
    }

    private void cleanupWallpaper() {
        deleteFile(WALLPAPER_FILE_NAME);
        mSwitcher.showNext();
    }

    /**
     * Background task to load the photo from Flickr. The task loads the bitmap,
     * then scale it to the appropriate dimension. The task ends by readjusting
     * the activity's layout so that everything aligns correctly.
     */
    private class LoadPhotoTask extends UserTask<Object, Void, Bitmap> {
        public Bitmap doInBackground(Object... params) {
            Bitmap bitmap = ((Flickr.Photo) params[0]).loadPhotoBitmap(Flickr.PhotoSize.MEDIUM);
            if (bitmap == null) {
                bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.not_found);
            }

            final int width = (Integer) params[1];
            final int height = (Integer) params[2];

            final Bitmap framed = ImageUtilities.scaleAndFrame(bitmap, width, height);
            bitmap.recycle();

            return framed;
        }

        @Override
        public void onPostExecute(Bitmap result) {
            mPhotoView.setImageBitmap(result);

            // Find by how many pixels the title and date must be shifted on the
            // horizontal axis to be left aligned with the photo
            final int offsetX = (mPhotoView.getMeasuredWidth() - result.getWidth()) / 2;

            // Forces the ImageView to have the same size as its embedded bitmap
            // This will remove the empty space between the title/date pair and
            // the photo itself
            LinearLayout.LayoutParams params;
            params = (LinearLayout.LayoutParams) mPhotoView.getLayoutParams();
            params.height = result.getHeight();
            params.weight = 0.0f;
            mPhotoView.setLayoutParams(params);

            params = (LinearLayout.LayoutParams) mPhotoTitle.getLayoutParams();
            params.leftMargin = offsetX;
            mPhotoTitle.setLayoutParams(params);

            params = (LinearLayout.LayoutParams) mPhotoDate.getLayoutParams();
            params.leftMargin = offsetX;
            mPhotoDate.setLayoutParams(params);

            mSwitcher.showNext();
            mContainer.startAnimation(AnimationUtils.loadAnimation(ViewPhotoActivity.this,
                    R.anim.fade_in));
            mContainer.setVisibility(View.VISIBLE);

            mTask = null;            
        }
    }

    /**
     * Background task to crop a large version of the image. The cropped result will
     * be set as a wallpaper. The tasks sarts by showing the progress bar, then
     * downloads the large version of hthe photo into a temporary file and ends by
     * sending an intent to the Camera application to crop the image.
     */
    private class CropWallpaperTask extends UserTask<Flickr.Photo, Void, Boolean> {
        private File mFile;

        @Override
        public void onPreExecute() {
            mFile = getFileStreamPath(WALLPAPER_FILE_NAME);
            mSwitcher.showNext();
        }

        public Boolean doInBackground(Flickr.Photo... params) {
            boolean success = false;

            OutputStream out = null;
            try {
                out = openFileOutput(mFile.getName(), MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
                Flickr.get().downloadPhoto(params[0], Flickr.PhotoSize.LARGE, out);
                success = true;
            } catch (FileNotFoundException e) {
                android.util.Log.e(Flickr.LOG_TAG, "Could not download photo", e);
                success = false;
            } catch (IOException e) {
                android.util.Log.e(Flickr.LOG_TAG, "Could not download photo", e);
                success = false;
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        success = false;
                    }
                }
            }

            return success;
        }

        @Override
        public void onPostExecute(Boolean result) {
            if (!result) {
                cleanupWallpaper();
                showWallpaperError();
            } else {
                final int width = getWallpaperDesiredMinimumWidth();
                final int height = getWallpaperDesiredMinimumHeight();

                final Intent intent = new Intent("com.android.camera.action.CROP");
                intent.setClassName("com.android.camera", "com.android.camera.CropImage");
                intent.setData(Uri.fromFile(mFile));
                intent.putExtra("outputX", width);
                intent.putExtra("outputY", height);
                intent.putExtra("aspectX", width);
                intent.putExtra("aspectY", height);
                intent.putExtra("scale", true);
                intent.putExtra("noFaceDetection", true);
                intent.putExtra("output", Uri.parse("file:/" + mFile.getAbsolutePath()));

                startActivityForResult(intent, REQUEST_CROP_IMAGE);
            }

            mTask = null;
        }
    }

    /**
     * Background task to set the cropped image as the wallpaper. The task simply
     * open the temporary file and sets it as the new wallpaper. The task ends by
     * deleting the temporary file and display a message to the user.
     */
    private class SetWallpaperTask extends UserTask<Void, Void, Boolean> {
        public Boolean doInBackground(Void... params) {
            boolean success = false;
            InputStream in = null;
            try {
                in = openFileInput(WALLPAPER_FILE_NAME);
                setWallpaper(in);
                success = true;
            } catch (IOException e) {
                success = false;
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        success = false;
                    }
                }
            }
            return success;
        }

        @Override
        public void onPostExecute(Boolean result) {
            cleanupWallpaper();

            if (!result) {
                showWallpaperError();
            } else {
                showWallpaperSuccess();
            }

            mTask = null;
        }
    }

    private class ShowRadarTask extends UserTask<Flickr.Photo, Void, Flickr.Location> {
        public Flickr.Location doInBackground(Flickr.Photo... params) {
            return Flickr.get().getLocation(params[0]);
        }

        @Override
        public void onPostExecute(Flickr.Location location) {
            if (location != null) {
                final Intent intent = new Intent(RADAR_ACTION);
                intent.putExtra(RADAR_EXTRA_LATITUDE, location.getLatitude());
                intent.putExtra(RADAR_EXTRA_LONGITUDE, location.getLongitude());

                try {
                    startActivity(intent);
                } catch (ActivityNotFoundException e) {
                    Toast.makeText(ViewPhotoActivity.this, R.string.error_cannot_find_radar,
                        Toast.LENGTH_SHORT).show();
                }
            } else {
                Toast.makeText(ViewPhotoActivity.this, R.string.error_cannot_find_location,
                        Toast.LENGTH_SHORT).show();
            }
        }
    }
}

Other Android examples (source code examples)

Here is a short list of links related to this Android ViewPhotoActivity.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.