2 * Copyright 2014 Gustavo Martin Morcuende
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package name.gumartinm.weather.information.fragment.map;
18 import java.io.IOException;
19 import java.util.List;
20 import java.util.Locale;
22 import android.app.Activity;
23 import android.content.Context;
24 import android.location.Address;
25 import android.location.Geocoder;
26 import android.os.AsyncTask;
27 import android.os.Bundle;
28 import android.support.v4.app.Fragment;
29 import android.util.Log;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.ViewGroup;
34 import name.gumartinm.weather.information.R;
35 import name.gumartinm.weather.information.model.WeatherLocation;
38 * {@link http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html}
41 public class MapProgressFragment extends Fragment {
45 * Callback interface through which the fragment will report the
46 * task's progress and results back to the Activity.
48 public static interface TaskCallbacks {
49 void onPostExecute(final WeatherLocation weatherLocation);
52 private TaskCallbacks mCallbacks;
55 public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
56 final Bundle savedInstanceState) {
58 // Inflate the layout for this fragment
59 return inflater.inflate(R.layout.weather_map_progress, container, false);
63 * This method will only be called once when the retained
64 * Fragment is first created.
67 public void onCreate(Bundle savedInstanceState) {
68 super.onCreate(savedInstanceState);
70 // Retain this fragment across configuration changes.
71 this.setRetainInstance(true);
73 final Bundle bundle = this.getArguments();
74 double latitude = bundle.getDouble("latitude");
75 double longitude = bundle.getDouble("longitude");
77 // Create and execute the background task.
78 new GetAddressTask(this.getActivity().getApplicationContext()).execute(latitude, longitude);
82 * Hold a reference to the parent Activity so we can report the
83 * task's current progress and results. The Android framework
84 * will pass us a reference to the newly created Activity after
85 * each configuration change.
88 public void onAttach(final Activity activity) {
89 super.onAttach(activity);
90 mCallbacks = (TaskCallbacks) activity;
94 * Set the callback to null so we don't accidentally leak the
98 // public void onDetach() {
100 // mCallbacks = null;
104 * I am not using onDetach because there are problems when my activity goes to background.
106 * {@link http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html}
109 public void onPause() {
114 private class GetAddressTask extends AsyncTask<Object, Void, WeatherLocation> {
115 private static final String TAG = "GetAddressTask";
116 // Store the context passed to the AsyncTask when the system instantiates it.
117 private final Context localContext;
119 private GetAddressTask(final Context context) {
120 this.localContext = context;
124 protected WeatherLocation doInBackground(final Object... params) {
125 final double latitude = (Double) params[0];
126 final double longitude = (Double) params[1];
128 WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
130 weatherLocation = this.getLocation(latitude, longitude);
131 } catch (final Throwable e) { // Hopefully nothing goes wrong because of catching Throwable.
132 Log.e(TAG, "GetAddressTask doInBackground exception: ", e);
135 return weatherLocation;
139 protected void onPostExecute(final WeatherLocation weatherLocation) {
141 // Call updateUI on the UI thread.
142 if (mCallbacks != null) {
143 mCallbacks.onPostExecute(weatherLocation);
147 private WeatherLocation getLocation(final double latitude, final double longitude) throws IOException {
148 // TODO: i18n Locale.getDefault()
149 final Geocoder geocoder = new Geocoder(this.localContext, Locale.US);
150 final List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
153 WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
155 if (addresses != null && addresses.size() > 0) {
156 if (addresses.get(0).getLocality() != null) {
157 weatherLocation.setCity(addresses.get(0).getLocality());
159 if(addresses.get(0).getCountryName() != null) {
160 weatherLocation.setCountry(addresses.get(0).getCountryName());
164 return weatherLocation;
167 private WeatherLocation doDefaultLocation(final double latitude, final double longitude) {
169 String city = this.localContext.getString(R.string.city_not_found);
170 String country = this.localContext.getString(R.string.country_not_found);
172 return new WeatherLocation()
173 .setLatitude(latitude)
174 .setLongitude(longitude)
176 .setCountry(country);