Java tutorial
/* * Copyright (C) 2012 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.cm.android.beercellar.ui; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.os.Vibrator; import android.support.v4.app.Fragment; import android.support.v4.app.NavUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RatingBar; import android.widget.TextView; import android.widget.Toast; import com.cm.android.beercellar.db.Note; import com.cm.android.beercellar.db.NotesDbAdapter; import com.cm.android.beercellar.provider.Images; import com.cm.android.beercellar.util.AsyncTask; import com.cm.android.beercellar.util.Configuration; import com.cm.android.beercellar.util.ImageFetcher; import com.cm.android.beercellar.util.ImageWorker; import com.cm.android.beercellar.util.Utils; import com.cm.beer.activity.lite.AnalyticsTrackers; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.Tracker; //import com.google.api.client.extensions.android.http.AndroidHttp; //import com.google.api.client.googleapis.json.GoogleJsonResponseException; //import com.google.api.client.http.HttpTransport; //import com.google.api.client.json.JsonFactory; //import com.google.api.client.json.gson.GsonFactory; //import com.google.api.services.vision.v1.Vision; //import com.google.api.services.vision.v1.VisionRequestInitializer; //import com.google.api.services.vision.v1.model.AnnotateImageRequest; //import com.google.api.services.vision.v1.model.BatchAnnotateImagesRequest; //import com.google.api.services.vision.v1.model.BatchAnnotateImagesResponse; //import com.google.api.services.vision.v1.model.Feature; //import com.google.api.services.vision.v1.model.Image; import com.google.api.client.http.ByteArrayContent; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; import com.google.api.client.http.HttpRequestInitializer; import com.google.api.client.http.HttpResponse; import com.google.api.client.http.HttpTransport; import com.google.api.client.http.HttpUnsuccessfulResponseHandler; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.util.ExponentialBackOff; import com.cm.beer.activity.lite.R; import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.TimeZone; /** * This fragment will populate the children of the ViewPager from {@link ImageDetailActivity}. */ public class ImageDetailFragment extends Fragment implements ImageWorker.OnImageLoadedListener, ImageWorker.OnImageDeletedListener { private static final String ROW_ID = "row_id"; private static final String IMAGE_DATA_EXTRA = "extra_image_data"; private static final String IMAGE_THUMBNAIL_DATA_EXTRA = "extra_thumbnail_image_data"; private String mImageUrl; private String mThumbnailUrl; private ImageView mImageView; private ProgressBar mProgressBar; private ImageFetcher mImageFetcher; private RatingBar mRatingBar; private EditText mTextExtract; private EditText mNotes; private ImageView mSave; private String sTag = ImageDetailFragment.class.getName(); //@author anshu private Tracker mTracker; private AdView mAdView; SimpleDateFormat mDateFormat = new SimpleDateFormat("MMM d, yyyy"); // Stateful Field private Long mRowId; private boolean mIsNew; private NotesDbAdapter mDbHelper; private Vibrator mVibrator; private TextView mDateCreated; private TextView mDateUpdated; private AutoCompleteTextView mBeer; /** * Factory method to generate a new instance of the fragment given an image number. * * @param imageUrl The image url to load * @return A new instance of ImageDetailFragment with imageNum extras */ public static ImageDetailFragment newInstance(String imageUrl, String imageThumbnailUrl) { final ImageDetailFragment f = new ImageDetailFragment(); final Bundle args = new Bundle(); args.putString(IMAGE_DATA_EXTRA, imageUrl); args.putString(IMAGE_THUMBNAIL_DATA_EXTRA, imageThumbnailUrl); f.setArguments(args); return f; } /** * Empty constructor as per the Fragment documentation */ public ImageDetailFragment() { } /** * Populate image using a url from extras, use the convenience factory method * to create this fragment. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mImageUrl = getArguments() != null ? getArguments().getString(IMAGE_DATA_EXTRA) : null; mThumbnailUrl = getArguments() != null ? getArguments().getString(IMAGE_THUMBNAIL_DATA_EXTRA) : null; mRowId = Utils.extractRowIdFromFileName(mImageUrl); mTracker = Utils.getAnalyticsTracker(getActivity(), AnalyticsTrackers.Target.APP); //required to set the options menu setHasOptionsMenu(true); mVibrator = (Vibrator) getActivity().getSystemService(getActivity().VIBRATOR_SERVICE); // if (mRowId == 0L) { // Log.w(sTag, "onCreate::ID is ZERO!!!"); // getActivity().finish(); // } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate and locate the main ImageView final View v = inflater.inflate(R.layout.image_detail_fragment, container, false); mImageView = (ImageView) v.findViewById(R.id.imageView); mProgressBar = (ProgressBar) v.findViewById(R.id.progressbar); //@author anshu: //Admob mAdView = (AdView) v.findViewById(R.id.adView); mRatingBar = (RatingBar) v.findViewById(R.id.rating); mTextExtract = (EditText) v.findViewById(R.id.text_extract); mNotes = (EditText) v.findViewById(R.id.notes); mSave = (ImageView) v.findViewById(R.id.save); mDateCreated = (TextView) v.findViewById(R.id.date_created_label); mDateUpdated = (TextView) v.findViewById(R.id.date_updated_label); mBeer = (AutoCompleteTextView) v.findViewById(R.id.beer); return v; } @Override public void onStart() { super.onStart(); new android.os.AsyncTask<Object, Void, Void>() { @Override protected Void doInBackground(Object... params) { try { //GA mTracker.setScreenName("ImageDetail"); mTracker.send(new HitBuilders.ScreenViewBuilder().build()); } catch (Throwable e) { //do nothing } finally { } return null; } @Override protected void onPostExecute(Void aVoid) { //AdMob AdRequest adRequest = new AdRequest.Builder().build(); mAdView.loadAd(adRequest); //beer adapter mBeer.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.list_item, Utils.BEERS)); } }.execute(); //display the other contents mRatingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() { @Override public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) { } }); mSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mVibrator.vibrate(250); save(); getActivity().finish(); } }); load(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Use the parent activity to load the image asynchronously into the ImageView (so a single // cache can be used over all pages in the ViewPager if (ImageDetailActivity.class.isInstance(getActivity())) { mImageFetcher = ((ImageDetailActivity) getActivity()).getImageFetcher(); mImageFetcher.loadImage(mImageUrl, mImageView, this); //database opened and managed by over arching activity mDbHelper = ((ImageDetailActivity) getActivity()).getDbHelper(); } } @Override public void onDestroy() { super.onDestroy(); if (mImageView != null) { // Cancel any pending image work ImageWorker.cancelWork(mImageView); mImageView.setImageDrawable(null); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.image_detail_menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(getActivity()); return true; case R.id.delete_menu: deleteImage(); return true; } return super.onOptionsItemSelected(item); } private void deleteImage() { AlertDialog.Builder builder = new AlertDialog.Builder(ImageDetailFragment.this.getActivity()); builder.setMessage("Delete?").setPositiveButton("Delete now", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { // Yes-code mProgressBar.setVisibility(View.VISIBLE); //String[] params = {mImageUrl, mThumbnailUrl}; //new DeleteImageAsyncTask().execute(params); try { //delete files under Pictures File imageFile = new File(mImageUrl); File thumbnailFile = new File(mThumbnailUrl); //delete thumbnail first for better ux if (thumbnailFile.delete() && imageFile.delete()) { List<Object> data = new ArrayList<Object>(); //delete thumbnail first data.add(mThumbnailUrl); data.add(mImageUrl); //delete files in the cache mImageFetcher.deleteImages(data, ImageDetailFragment.this); //database mDbHelper.deleteNote(mRowId); } else { Log.e(ImageDetailFragment.class.getName(), "Unable to delete files"); Toast.makeText(getActivity(), "Unable to delete", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Log.e(ImageDetailFragment.class.getName(), e.getMessage()); } //getActivity().finish(); } }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }).show(); } @Override public void onImageLoaded(boolean success) { // Set loading spinner to gone once image has loaded. Cloud also show // an error view here if needed. mProgressBar.setVisibility(View.GONE); } //TODO: Load called multiple times, once for each grid item private void load() { Log.i(sTag, "load"); try { if (mRowId != null) { Note note = mDbHelper.fetchNote(mRowId); if (note != null) { String ratingStr = note.rating; mRatingBar.setRating(Float.valueOf(ratingStr)); mBeer.setText(note.beer); mTextExtract.setText(note.textExtract); mNotes.setText(note.notes); String dateAdded = "Added on " + mDateFormat.format(note.created); mDateCreated.setText(dateAdded); String dataUpdated = "Last updated on " + mDateFormat.format(note.updated); mDateUpdated.setText(dataUpdated); } } } catch (Throwable e) { Log.e(sTag, "error: " + ((e.getMessage() != null) ? e.getMessage().replace(" ", "_") : ""), e); } } private void save() { try { Note note = new Note(); note.id = mRowId; note.beer = mBeer.getText().toString(); note.rating = String.valueOf(mRatingBar.getRating()); note.textExtract = mTextExtract.getText().toString(); note.notes = mNotes.getText().toString(); //default to Y note.share = "Y"; note.picture = mRowId + Utils.PICTURES_EXTENSION; //note.share = mShare.isChecked() ? "Y" : "N"; if (mIsNew) { mDbHelper.createNote(note); mIsNew = false; } else { mDbHelper.updateNote(note); } // Do the real work in an async task, because we need to use the network anyway new android.os.AsyncTask<Object, Void, Void>() { @Override protected Void doInBackground(Object... params) { NotesDbAdapter dbHelper = null; long rowId = (Long) params[0]; try { HttpTransport httpTransport = new NetHttpTransport(); HttpRequestFactory requestFactory = httpTransport.createRequestFactory(new MyInitializer()); JSONObject jsonObject = new JSONObject(); dbHelper = new NotesDbAdapter(getActivity()); dbHelper.open(); Note note = dbHelper.fetchNote(rowId); jsonObject.put("rowId", note.id); jsonObject.put("beer", note.beer); jsonObject.put("rating", note.rating); jsonObject.put("textExtract", note.textExtract); jsonObject.put("notes", note.notes); jsonObject.put("uri", note.uri); jsonObject.put("timeCreatedMs", note.created); jsonObject.put("timeCreatedTimeZoneOffsetMs", TimeZone.getDefault().getRawOffset()); jsonObject.put("timeUpdatedMs", note.updated); jsonObject.put("timeUpdatedTimeZoneOffsetMs", TimeZone.getDefault().getRawOffset()); HttpResponse httpPostResponse = null; try { httpPostResponse = requestFactory.buildPutRequest( new GenericUrl(Configuration.CONTENTS_URL), new ByteArrayContent("application/json", jsonObject.toString().getBytes())) .execute(); Log.i(sTag, "HTTP STATUS:: " + httpPostResponse.getStatusCode()); } finally { httpPostResponse.disconnect(); } } catch (Throwable e) { Log.e(sTag, "error: " + ((e.getMessage() != null) ? e.getMessage().replace(" ", "_") : ""), e); } finally { if (dbHelper != null) dbHelper.close(); } return null; } }.execute(mRowId); } catch (Throwable e) { Log.e(sTag, "error: " + ((e.getMessage() != null) ? e.getMessage().replace(" ", "_") : ""), e); } } private static class MyInitializer implements HttpRequestInitializer, HttpUnsuccessfulResponseHandler { @Override public boolean handleResponse(HttpRequest request, HttpResponse response, boolean retrySupported) throws IOException { Log.d("MyInitializer", response.getStatusCode() + " " + response.getStatusMessage()); if (response.getStatusCode() == 503) { //retry return true; } return false; } @Override public void initialize(HttpRequest request) throws IOException { ExponentialBackOff backoff = new ExponentialBackOff.Builder().setInitialIntervalMillis(1000) .setMaxElapsedTimeMillis(900000).setMaxIntervalMillis(10000).setMultiplier(1.5) .setRandomizationFactor(0.5).build(); request.setUnsuccessfulResponseHandler(new HttpBackOffUnsuccessfulResponseHandler(backoff)); } } @Override public void onImageDeleted(boolean success) { //getActivity().getSupportFragmentManager().popBackStack(); mProgressBar.setVisibility(View.GONE); // Do the real work in an async task, because we need to use the network anyway new android.os.AsyncTask<Object, Void, Void>() { @Override protected Void doInBackground(Object... params) { long rowId = (Long) params[0]; try { HttpTransport httpTransport = new NetHttpTransport(); HttpRequestFactory requestFactory = httpTransport.createRequestFactory(new MyInitializer()); GenericUrl genericUrl = new GenericUrl(Configuration.CONTENTS_URL + "/" + rowId + "/" + System.currentTimeMillis() + "/" + TimeZone.getDefault().getRawOffset()); HttpResponse httpPostResponse = null; try { httpPostResponse = requestFactory.buildDeleteRequest(genericUrl).execute(); Log.i(sTag, "HTTP STATUS:: " + httpPostResponse.getStatusCode()); } finally { httpPostResponse.disconnect(); } } catch (Throwable e) { Log.e(sTag, "error: " + ((e.getMessage() != null) ? e.getMessage().replace(" ", "_") : ""), e); } return null; } }.execute(mRowId); getActivity().finish(); } /** * @author anshu */ private class DeleteImageAsyncTask extends AsyncTask<String, Void, Void> { @Override protected Void doInBackground(String... strings) { String mImageUrl = strings[0]; String mImageThumbnailUrl = strings[1]; try { //delete files under Pictures File imageFile = new File(mImageUrl); File thumbnailFile = new File(mImageUrl); //delete thumbnail first for better ux if (thumbnailFile.delete() && imageFile.delete()) { List<Object> data = new ArrayList<Object>(); //delete thumbnail first data.add(mImageThumbnailUrl); data.add(mImageUrl); //delete files in the cache mImageFetcher.deleteImages(data, ImageDetailFragment.this); } else { Log.e(ImageDetailFragment.class.getName(), "Unable to delete files"); Toast.makeText(getActivity(), "Unable to delete", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { Log.e(ImageDetailFragment.class.getName(), e.getMessage()); } return null; } @Override protected void onPostExecute(Void result) { } } }