aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDvTonder <david.vantonder@gmail.com>2012-12-27 23:15:20 -0500
committerDvTonder <david.vantonder@gmail.com>2012-12-27 23:23:49 -0500
commit64090cd997e4f6a9b3f02f5ba96e32e297f6403e (patch)
tree13bcd3ea42015aaf2f59b69625610fc8ca2132ce /src
parente8a79ed06bfa47b05a883c2b9722cd5ccadb8b4d (diff)
downloadandroid_packages_apps_LockClock-64090cd997e4f6a9b3f02f5ba96e32e297f6403e.tar.gz
android_packages_apps_LockClock-64090cd997e4f6a9b3f02f5ba96e32e297f6403e.tar.bz2
android_packages_apps_LockClock-64090cd997e4f6a9b3f02f5ba96e32e297f6403e.zip
Initial commit
Diffstat (limited to 'src')
-rw-r--r--src/com/cyanogenmod/lockclock/ClockWidgetProvider.java71
-rw-r--r--src/com/cyanogenmod/lockclock/ClockWidgetService.java379
-rw-r--r--src/com/cyanogenmod/lockclock/MainActivity.java333
-rw-r--r--src/com/cyanogenmod/lockclock/WidgetUtils.java71
-rw-r--r--src/com/cyanogenmod/lockclock/misc/Constants.java25
-rw-r--r--src/com/cyanogenmod/lockclock/weather/HttpRetriever.java152
-rw-r--r--src/com/cyanogenmod/lockclock/weather/WeatherInfo.java115
-rw-r--r--src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java177
-rw-r--r--src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java41
9 files changed, 1364 insertions, 0 deletions
diff --git a/src/com/cyanogenmod/lockclock/ClockWidgetProvider.java b/src/com/cyanogenmod/lockclock/ClockWidgetProvider.java
new file mode 100644
index 0000000..a4a2dfc
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/ClockWidgetProvider.java
@@ -0,0 +1,71 @@
+package com.cyanogenmod.lockclock;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import com.cyanogenmod.lockclock.misc.Constants;
+
+import java.util.Date;
+
+public class ClockWidgetProvider extends AppWidgetProvider {
+
+ private static final String TAG = "ClockWidgetProvider";
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ Log.i(TAG, "onUpdate Called");
+
+ // Get all ids
+ ComponentName thisWidget = new ComponentName(context, ClockWidgetProvider.class);
+ int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
+
+ // Build the intent to call the service
+ Intent intent = new Intent(context.getApplicationContext(), ClockWidgetService.class);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
+
+ // Update the widget via the service - once only, to get things started
+ Log.i(TAG, "Do a single update");
+ context.startService(intent);
+
+ // Load the required settings from preferences
+ SharedPreferences prefs = context.getSharedPreferences("LockClock", Context.MODE_MULTI_PROCESS);
+ int updateFrequency = prefs.getInt(Constants.UPDATE_CHECK_PREF, Constants.UPDATE_FREQ_DEFAULT);
+
+ // If not set to manual updates, handle the ongoing updatesbased on the defined frequency
+ if (updateFrequency > 0) {
+ Log.i(TAG, "Scheduling future, repeating update checks.");
+ scheduleUpdateService(context, intent, updateFrequency * 60000);
+ }
+ }
+
+ private void scheduleUpdateService(Context context, Intent intent, int updateFrequency) {
+ // Load the required settings from preferences
+ SharedPreferences prefs = context.getSharedPreferences("LockClock", Context.MODE_MULTI_PROCESS);
+ Date lastCheck = new Date(prefs.getLong(Constants.LAST_UPDATE_CHECK_PREF, 0));
+
+ // Get the intent ready
+ PendingIntent pi = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ // Clear any old alarms and schedule the new alarm
+ AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ am.cancel(pi);
+ am.setRepeating(AlarmManager.RTC_WAKEUP, lastCheck.getTime() + updateFrequency, updateFrequency, pi);
+ }
+
+ @Override
+ public void onDeleted (Context context, int[] appWidgetIds) { }
+
+ @Override
+ public void onEnabled (Context context) { }
+
+ @Override
+ public void onDisabled (Context context) { }
+
+}
diff --git a/src/com/cyanogenmod/lockclock/ClockWidgetService.java b/src/com/cyanogenmod/lockclock/ClockWidgetService.java
new file mode 100644
index 0000000..6cc048f
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/ClockWidgetService.java
@@ -0,0 +1,379 @@
+/*
+ * 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.cyanogenmod.lockclock;
+
+import android.app.PendingIntent;
+import android.app.Service;
+import android.appwidget.AppWidgetManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.cyanogenmod.lockclock.misc.Constants;
+import com.cyanogenmod.lockclock.weather.HttpRetriever;
+import com.cyanogenmod.lockclock.weather.WeatherInfo;
+import com.cyanogenmod.lockclock.weather.WeatherXmlParser;
+import com.cyanogenmod.lockclock.weather.YahooPlaceFinder;
+
+import org.w3c.dom.Document;
+
+import java.io.IOException;
+import java.util.Date;
+
+public class ClockWidgetService extends Service {
+ private static final String TAG = "ClockWidgetService";
+ private static final boolean DEBUG = true;
+
+ private Context mContext;
+ private int[] mWidgetIds;
+ private AppWidgetManager mAppWidgetManager;
+
+ @Override
+ public void onCreate() {
+ mContext = getApplicationContext();
+ mAppWidgetManager = AppWidgetManager.getInstance(mContext);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ // Iterate through all the widgets supported by this provider
+ mWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ if (mWidgetIds != null && mWidgetIds.length != 0) {
+ refreshWeather();
+ }
+
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ /*
+ * CyanogenMod Lock screen Weather related functionality
+ */
+ private static final String URL_YAHOO_API_WEATHER = "http://weather.yahooapis.com/forecastrss?w=%s&u=";
+ private static WeatherInfo mWeatherInfo = new WeatherInfo();
+ private static final int QUERY_WEATHER = 0;
+ private static final int UPDATE_WEATHER = 1;
+ private boolean mWeatherRefreshing;
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case QUERY_WEATHER:
+ Thread queryWeather = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ LocationManager locationManager =
+ (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+
+ final ContentResolver resolver = getBaseContext().getContentResolver();
+ boolean useCustomLoc = false; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_USE_CUSTOM_LOCATION, 0) == 1;
+ String customLoc = "Toronto, Canada"; //Settings.System.getString(resolver,
+ //Settings.System.WEATHER_CUSTOM_LOCATION);
+ String woeid = null;
+
+ // custom location
+ if (customLoc != null && useCustomLoc) {
+ try {
+ woeid = YahooPlaceFinder.GeoCode(mContext, customLoc);
+ if (DEBUG)
+ Log.d(TAG, "Yahoo location code for " + customLoc + " is " + woeid);
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR: Could not get Location code");
+ e.printStackTrace();
+ }
+ // network location
+ } else {
+ Criteria crit = new Criteria();
+ crit.setAccuracy(Criteria.ACCURACY_COARSE);
+ String bestProvider = locationManager.getBestProvider(crit, true);
+ Location loc = null;
+ if (bestProvider != null) {
+ if (DEBUG)
+ Log.d(TAG, "getLastKnownLocation - bestProvider");
+ loc = locationManager.getLastKnownLocation(bestProvider);
+ } else {
+ if (DEBUG)
+ Log.d(TAG, "getLastKnownLocation - Passive provider");
+ loc = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
+ }
+ try {
+ if (DEBUG)
+ Log.d(TAG, "Looking for Yahoo location code for current geolocation. Loc = " + loc);
+ if (loc != null) {
+ woeid = YahooPlaceFinder.reverseGeoCode(mContext, loc.getLatitude(),
+ loc.getLongitude());
+ if (DEBUG)
+ Log.d(TAG, "Yahoo location code for current geolocation is " + woeid);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR: Could not get Location code");
+ e.printStackTrace();
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Location code is " + woeid);
+ }
+ WeatherInfo w = null;
+ if (woeid != null) {
+ try {
+ w = parseXml(getDocument(woeid));
+ } catch (Exception e) {
+ }
+ }
+ Message msg = Message.obtain();
+ msg.what = UPDATE_WEATHER;
+ msg.obj = w;
+ mHandler.sendMessage(msg);
+ }
+ });
+ mWeatherRefreshing = true;
+ queryWeather.setPriority(Thread.MIN_PRIORITY);
+ queryWeather.start();
+ break;
+ case UPDATE_WEATHER:
+ WeatherInfo w = (WeatherInfo) msg.obj;
+ if (w != null) {
+ // Store the last update check time
+ Date d = new Date();
+ SharedPreferences prefs = getSharedPreferences("LockClock", Context.MODE_MULTI_PROCESS);
+ prefs.edit().putLong(Constants.LAST_UPDATE_CHECK_PREF, d.getTime()).apply();
+
+ // Update the weather info
+ mWeatherRefreshing = false;
+ setWeatherData(w);
+ mWeatherInfo = w;
+ } else {
+ mWeatherRefreshing = false;
+ if (mWeatherInfo.temp.equals(WeatherInfo.NODATA)) {
+ setNoWeatherData();
+ } else {
+ setWeatherData(mWeatherInfo);
+ }
+ }
+ break;
+ }
+ }
+ };
+
+ /**
+ * Reload the weather forecast
+ */
+ private void refreshWeather() {
+ final ContentResolver resolver = getBaseContext().getContentResolver();
+ SharedPreferences prefs = mContext.getSharedPreferences("LockClock", Context.MODE_MULTI_PROCESS);
+ boolean showWeather = true; //Settings.System.getInt(resolver,Settings.System.LOCKSCREEN_WEATHER, 0) == 1;
+
+ if (showWeather) {
+ //showRefreshing();
+
+ // Load the required settings from preferences
+ final long interval = prefs.getInt(Constants.UPDATE_CHECK_PREF, Constants.UPDATE_FREQ_DEFAULT);
+ boolean manualSync = (interval == Constants.UPDATE_FREQ_MANUAL);
+ if (!manualSync && (((System.currentTimeMillis() - mWeatherInfo.last_sync) / 60000) >= interval)) {
+ if (!mWeatherRefreshing) {
+ mHandler.sendEmptyMessage(QUERY_WEATHER);
+ }
+ } else if (manualSync && mWeatherInfo.last_sync == 0) {
+ setNoWeatherData();
+ } else {
+ setWeatherData(mWeatherInfo);
+ }
+ } else {
+ /* Hide the Weather panel view
+ if (mRemoteViews != null) {
+ mRemoteViews.setViewVisibility(R.id.weather_panel, View.GONE);
+ }*/
+ }
+ }
+
+ /**
+ * Indicate that the widget is refreshing
+ */
+ private void showRefreshing() {
+ final Resources res = getBaseContext().getResources();
+ RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(), R.layout.digital_appwidget);
+ remoteViews.setTextViewText(R.id.weather_condition, res.getString(R.string.weather_refreshing));
+ for (int widgetId : mWidgetIds) {
+ if (DEBUG)
+ Log.d(TAG, "Showing refreshing status for Widget ID:" + widgetId);
+ mAppWidgetManager.updateAppWidget(widgetId, remoteViews);
+ }
+ }
+
+ /**
+ * Display the weather information
+ * @param w
+ */
+ private void setWeatherData(WeatherInfo w) {
+ final ContentResolver resolver = getBaseContext().getContentResolver();
+ final Resources res = getBaseContext().getResources();
+ boolean showLocation = true; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_SHOW_LOCATION, 1) == 1;
+ boolean showTimestamp = true; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_SHOW_TIMESTAMP, 1) == 1;
+ boolean invertLowhigh = false; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_INVERT_LOWHIGH, 0) == 1;
+ RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(), R.layout.digital_appwidget);
+
+ // Weather Image
+ String conditionCode = w.condition_code;
+ String condition_filename = "weather_" + conditionCode;
+ int resID = res.getIdentifier(condition_filename, "drawable",
+ getBaseContext().getPackageName());
+
+ if (DEBUG)
+ Log.d("Weather", "Condition:" + conditionCode + " ID:" + resID);
+
+ if (resID != 0) {
+ remoteViews.setImageViewResource(R.id.weather_image, resID);
+ } else {
+ remoteViews.setImageViewResource(R.id.weather_image, R.drawable.weather_na);
+ }
+
+ // City
+ remoteViews.setTextViewText(R.id.weather_city, w.city);
+ remoteViews.setViewVisibility(R.id.weather_city, showLocation ? View.VISIBLE : View.GONE);
+
+ // Weather Condition
+ remoteViews.setTextViewText(R.id.weather_condition, w.condition);
+ remoteViews.setViewVisibility(R.id.weather_condition, View.VISIBLE);
+
+ // Weather Update Time
+ long now = System.currentTimeMillis();
+ if (now - w.last_sync < 60000) {
+ remoteViews.setTextViewText(R.id.update_time, res.getString(R.string.weather_last_sync_just_now));
+ } else {
+ remoteViews.setTextViewText(R.id.update_time, DateUtils.getRelativeTimeSpanString(
+ w.last_sync, now, DateUtils.MINUTE_IN_MILLIS));
+ }
+ remoteViews.setViewVisibility(R.id.update_time, showTimestamp ? View.VISIBLE : View.GONE);
+
+ // Weather Temps Panel
+ remoteViews.setTextViewText(R.id.weather_temp, w.temp);
+ remoteViews.setTextViewText(R.id.weather_low_high, invertLowhigh ? w.high + " | " + w.low : w.low + " | " + w.high);
+ remoteViews.setViewVisibility(R.id.weather_temps_panel, View.VISIBLE);
+
+ // Show the Weather panel view
+ remoteViews.setViewVisibility(R.id.weather_panel, View.VISIBLE);
+
+ // Register an onClickListener on Weather
+ Intent weatherClickIntent = new Intent(mContext, ClockWidgetProvider.class);
+ weatherClickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ weatherClickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, mWidgetIds);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, weatherClickIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ remoteViews.setOnClickPendingIntent(R.id.weather_panel, pendingIntent);
+
+ // Register an onClickListener on Clock
+ Intent clockClickIntent = new Intent(mContext, ClockWidgetProvider.class);
+ clockClickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ clockClickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, mWidgetIds);
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, clockClickIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ remoteViews.setOnClickPendingIntent(R.id.digital_clock, pi);
+
+ // Update all the widgets and stop
+ for (int widgetId : mWidgetIds) {
+ mAppWidgetManager.updateAppWidget(widgetId, remoteViews);
+ }
+ stopSelf();
+ }
+
+ /**
+ * There is no data to display, display 'empty' fields and the
+ * 'Tap to reload' message
+ */
+ private void setNoWeatherData() {
+ final Resources res = getBaseContext().getResources();
+ RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(), R.layout.digital_appwidget);
+ if (remoteViews != null) {
+ remoteViews.setImageViewResource(R.id.weather_image, R.drawable.weather_na);
+ remoteViews.setTextViewText(R.id.weather_city, res.getString(R.string.weather_no_data));
+ remoteViews.setViewVisibility(R.id.weather_city, View.VISIBLE);
+ remoteViews.setTextViewText(R.id.weather_condition, res.getString(R.string.weather_tap_to_refresh));
+ remoteViews.setViewVisibility(R.id.update_time, View.GONE);
+ remoteViews.setViewVisibility(R.id.weather_temps_panel, View.GONE);
+
+ // Show the Weather panel view
+ remoteViews.setViewVisibility(R.id.weather_panel, View.VISIBLE);
+ }
+
+ // Update all the widgets and stop
+ for (int widgetId : mWidgetIds) {
+ mAppWidgetManager.updateAppWidget(widgetId, remoteViews);
+ }
+ stopSelf();
+ }
+
+ /**
+ * Get the weather forecast XML document for a specific location
+ * @param woeid
+ * @return
+ */
+ private Document getDocument(String woeid) {
+ try {
+ boolean celcius = true; //Settings.System.getInt(getBaseContext().getContentResolver(),
+ //Settings.System.WEATHER_USE_METRIC, 1) == 1;
+ String urlWithDegreeUnit;
+
+ if (celcius) {
+ urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "c";
+ } else {
+ urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "f";
+ }
+
+ return new HttpRetriever().getDocumentFromURL(String.format(urlWithDegreeUnit, woeid));
+ } catch (IOException e) {
+ Log.e(TAG, "Error querying Yahoo weather");
+ }
+
+ return null;
+ }
+
+ /**
+ * Parse the weather XML document
+ * @param wDoc
+ * @return
+ */
+ private WeatherInfo parseXml(Document wDoc) {
+ try {
+ return new WeatherXmlParser(getBaseContext()).parseWeatherResponse(wDoc);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing Yahoo weather XML document");
+ e.printStackTrace();
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/com/cyanogenmod/lockclock/MainActivity.java b/src/com/cyanogenmod/lockclock/MainActivity.java
new file mode 100644
index 0000000..b16e838
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/MainActivity.java
@@ -0,0 +1,333 @@
+
+package com.cyanogenmod.lockclock;
+
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+
+import com.cyanogenmod.lockclock.weather.*;
+
+import org.w3c.dom.Document;
+
+import java.io.IOException;
+
+public class MainActivity extends Activity implements View.OnClickListener {
+
+ private static String TAG = "LockClock";
+ private boolean DEBUG = true;
+
+ private RelativeLayout mWeatherPanel, mWeatherTempsPanel;
+ private TextView mWeatherCity, mWeatherCondition, mWeatherLowHigh, mWeatherTemp, mWeatherUpdateTime;
+ private ImageView mWeatherImage;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.digital_appwidget);
+
+ // Weather panel
+ mWeatherPanel = (RelativeLayout) findViewById(R.id.weather_panel);
+ mWeatherCity = (TextView) findViewById(R.id.weather_city);
+ mWeatherCondition = (TextView) findViewById(R.id.weather_condition);
+ mWeatherImage = (ImageView) findViewById(R.id.weather_image);
+ mWeatherTemp = (TextView) findViewById(R.id.weather_temp);
+ mWeatherLowHigh = (TextView) findViewById(R.id.weather_low_high);
+ mWeatherUpdateTime = (TextView) findViewById(R.id.update_time);
+ mWeatherTempsPanel = (RelativeLayout) findViewById(R.id.weather_temps_panel);
+
+ // Hide Weather panel view until we know we need to show it.
+ if (mWeatherPanel != null) {
+ mWeatherPanel.setVisibility(View.GONE);
+ mWeatherPanel.setOnClickListener(this);
+ }
+
+ refreshWeather();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ //refreshWeather();
+ }
+
+ public void onClick(View v) {
+ if (v == mWeatherPanel) {
+ // Indicate we are refreshing
+ if (mWeatherCondition != null) {
+ mWeatherCondition.setText(R.string.weather_refreshing);
+ }
+
+ if (!mWeatherRefreshing) {
+ mHandler.sendEmptyMessage(QUERY_WEATHER);
+ }
+ }
+ }
+
+ protected void refresh() {
+ }
+
+ /*
+ * CyanogenMod Lock screen Weather related functionality
+ */
+ private static final String URL_YAHOO_API_WEATHER = "http://weather.yahooapis.com/forecastrss?w=%s&u=";
+ private static WeatherInfo mWeatherInfo = new WeatherInfo();
+ private static final int QUERY_WEATHER = 0;
+ private static final int UPDATE_WEATHER = 1;
+ private boolean mWeatherRefreshing;
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case QUERY_WEATHER:
+ Thread queryWeather = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ LocationManager locationManager = (LocationManager) getBaseContext().
+ getSystemService(Context.LOCATION_SERVICE);
+ final ContentResolver resolver = getBaseContext().getContentResolver();
+ boolean useCustomLoc = true; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_USE_CUSTOM_LOCATION, 0) == 1;
+ String customLoc = "Toronto, Canada"; //Settings.System.getString(resolver,
+ //Settings.System.WEATHER_CUSTOM_LOCATION);
+ String woeid = null;
+
+ // custom location
+ if (customLoc != null && useCustomLoc) {
+ try {
+ woeid = YahooPlaceFinder.GeoCode(getBaseContext().getApplicationContext(), customLoc);
+ if (DEBUG)
+ Log.d(TAG, "Yahoo location code for " + customLoc + " is " + woeid);
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR: Could not get Location code");
+ e.printStackTrace();
+ }
+ // network location
+ } else {
+ Criteria crit = new Criteria();
+ crit.setAccuracy(Criteria.ACCURACY_COARSE);
+ String bestProvider = locationManager.getBestProvider(crit, true);
+ Location loc = null;
+ if (bestProvider != null) {
+ loc = locationManager.getLastKnownLocation(bestProvider);
+ } else {
+ loc = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
+ }
+ try {
+ woeid = YahooPlaceFinder.reverseGeoCode(getBaseContext(), loc.getLatitude(),
+ loc.getLongitude());
+ if (DEBUG)
+ Log.d(TAG, "Yahoo location code for current geolocation is " + woeid);
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR: Could not get Location code");
+ e.printStackTrace();
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Location code is " + woeid);
+ }
+ WeatherInfo w = null;
+ if (woeid != null) {
+ try {
+ w = parseXml(getDocument(woeid));
+ } catch (Exception e) {
+ }
+ }
+ Message msg = Message.obtain();
+ msg.what = UPDATE_WEATHER;
+ msg.obj = w;
+ mHandler.sendMessage(msg);
+ }
+ });
+ mWeatherRefreshing = true;
+ queryWeather.setPriority(Thread.MIN_PRIORITY);
+ queryWeather.start();
+ break;
+ case UPDATE_WEATHER:
+ WeatherInfo w = (WeatherInfo) msg.obj;
+ if (w != null) {
+ mWeatherRefreshing = false;
+ setWeatherData(w);
+ mWeatherInfo = w;
+ } else {
+ mWeatherRefreshing = false;
+ if (mWeatherInfo.temp.equals(WeatherInfo.NODATA)) {
+ setNoWeatherData();
+ } else {
+ setWeatherData(mWeatherInfo);
+ }
+ }
+ break;
+ }
+ }
+ };
+
+ /**
+ * Reload the weather forecast
+ */
+ private void refreshWeather() {
+ final ContentResolver resolver = getBaseContext().getContentResolver();
+ boolean showWeather = true; //Settings.System.getInt(resolver,Settings.System.LOCKSCREEN_WEATHER, 0) == 1;
+
+ if (showWeather) {
+ final long interval = 5; //Settings.System.getLong(resolver,
+ //Settings.System.WEATHER_UPDATE_INTERVAL, 60); // Default to hourly
+ boolean manualSync = (interval == 0);
+ if (!manualSync && (((System.currentTimeMillis() - mWeatherInfo.last_sync) / 60000) >= interval)) {
+ if (!mWeatherRefreshing) {
+ mHandler.sendEmptyMessage(QUERY_WEATHER);
+ }
+ } else if (manualSync && mWeatherInfo.last_sync == 0) {
+ setNoWeatherData();
+ } else {
+ setWeatherData(mWeatherInfo);
+ }
+ } else {
+ // Hide the Weather panel view
+ if (mWeatherPanel != null) {
+ mWeatherPanel.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ /**
+ * Display the weather information
+ * @param w
+ */
+ private void setWeatherData(WeatherInfo w) {
+ final ContentResolver resolver = getBaseContext().getContentResolver();
+ final Resources res = getBaseContext().getResources();
+ boolean showLocation = true; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_SHOW_LOCATION, 1) == 1;
+ boolean showTimestamp = true; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_SHOW_TIMESTAMP, 1) == 1;
+ boolean invertLowhigh = false; //Settings.System.getInt(resolver,
+ //Settings.System.WEATHER_INVERT_LOWHIGH, 0) == 1;
+
+ if (mWeatherPanel != null) {
+ if (mWeatherImage != null) {
+ String conditionCode = w.condition_code;
+ String condition_filename = "weather_" + conditionCode;
+ int resID = res.getIdentifier(condition_filename, "drawable",
+ getBaseContext().getPackageName());
+
+ if (DEBUG)
+ Log.d("Weather", "Condition:" + conditionCode + " ID:" + resID);
+
+ if (resID != 0) {
+ mWeatherImage.setImageDrawable(res.getDrawable(resID));
+ } else {
+ mWeatherImage.setImageResource(R.drawable.weather_na);
+ }
+ }
+ if (mWeatherCity != null) {
+ mWeatherCity.setText(w.city);
+ mWeatherCity.setVisibility(showLocation ? View.VISIBLE : View.GONE);
+ }
+ if (mWeatherCondition != null && !mWeatherRefreshing) {
+ mWeatherCondition.setText(w.condition);
+ mWeatherCondition.setVisibility(View.VISIBLE);
+ }
+ if (mWeatherUpdateTime != null) {
+ long now = System.currentTimeMillis();
+ if (now - w.last_sync < 60000) {
+ mWeatherUpdateTime.setText(R.string.weather_last_sync_just_now);
+ } else {
+ mWeatherUpdateTime.setText(DateUtils.getRelativeTimeSpanString(
+ w.last_sync, now, DateUtils.MINUTE_IN_MILLIS));
+ }
+ mWeatherUpdateTime.setVisibility(showTimestamp ? View.VISIBLE : View.GONE);
+ }
+ if (mWeatherTempsPanel != null && mWeatherTemp != null && mWeatherLowHigh != null) {
+ mWeatherTemp.setText(w.temp);
+ mWeatherLowHigh.setText(invertLowhigh ? w.high + " | " + w.low : w.low + " | " + w.high);
+ mWeatherTempsPanel.setVisibility(View.VISIBLE);
+ }
+
+ // Show the Weather panel view
+ mWeatherPanel.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * There is no data to display, display 'empty' fields and the
+ * 'Tap to reload' message
+ */
+ private void setNoWeatherData() {
+
+ if (mWeatherPanel != null) {
+ if (mWeatherImage != null) {
+ mWeatherImage.setImageResource(R.drawable.weather_na);
+ }
+ if (mWeatherCity != null) {
+ mWeatherCity.setText(R.string.weather_no_data);
+ mWeatherCity.setVisibility(View.VISIBLE);
+ }
+ if (mWeatherCondition != null && !mWeatherRefreshing) {
+ mWeatherCondition.setText(R.string.weather_tap_to_refresh);
+ }
+ if (mWeatherUpdateTime != null) {
+ mWeatherUpdateTime.setVisibility(View.GONE);
+ }
+ if (mWeatherTempsPanel != null ) {
+ mWeatherTempsPanel.setVisibility(View.GONE);
+ }
+
+ // Show the Weather panel view
+ mWeatherPanel.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Get the weather forecast XML document for a specific location
+ * @param woeid
+ * @return
+ */
+ private Document getDocument(String woeid) {
+ try {
+ boolean celcius = true; //Settings.System.getInt(getBaseContext().getContentResolver(),
+ //Settings.System.WEATHER_USE_METRIC, 1) == 1;
+ String urlWithDegreeUnit;
+
+ if (celcius) {
+ urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "c";
+ } else {
+ urlWithDegreeUnit = URL_YAHOO_API_WEATHER + "f";
+ }
+
+ return new HttpRetriever().getDocumentFromURL(String.format(urlWithDegreeUnit, woeid));
+ } catch (IOException e) {
+ Log.e(TAG, "Error querying Yahoo weather");
+ }
+
+ return null;
+ }
+
+ /**
+ * Parse the weather XML document
+ * @param wDoc
+ * @return
+ */
+ private WeatherInfo parseXml(Document wDoc) {
+ try {
+ return new WeatherXmlParser(getBaseContext()).parseWeatherResponse(wDoc);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing Yahoo weather XML document");
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/src/com/cyanogenmod/lockclock/WidgetUtils.java b/src/com/cyanogenmod/lockclock/WidgetUtils.java
new file mode 100644
index 0000000..96e702c
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/WidgetUtils.java
@@ -0,0 +1,71 @@
+/*
+ * 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.cyanogenmod.lockclock;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.TypedValue;
+import android.widget.RemoteViews;
+
+public class WidgetUtils {
+ static final String TAG = "WidgetUtils";
+
+ public static void setClockSize(Context context, RemoteViews clock, float scale) {
+ float fontSize = context.getResources().getDimension(R.dimen.widget_big_font_size);
+ clock.setTextViewTextSize(
+ R.id.the_clock1, TypedValue.COMPLEX_UNIT_PX, fontSize * scale);
+ clock.setTextViewTextSize(
+ R.id.the_clock2, TypedValue.COMPLEX_UNIT_PX, fontSize * scale);
+ }
+
+ // Calculate the scale factor of the fonts in the widget
+ public static float getScaleRatio(Context context, Bundle options, int id) {
+ AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
+ if (options == null) {
+ options = widgetManager.getAppWidgetOptions(id);
+ }
+ if (options != null) {
+ int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
+ if (minWidth == 0) {
+ // No data , do no scaling
+ return 1f;
+ }
+ Resources res = context.getResources();
+ float ratio = minWidth / res.getDimension(R.dimen.def_digital_widget_width);
+ return (ratio > 1) ? 1 : ratio;
+ }
+ return 1;
+ }
+
+ // Decide if to show the list of world clock.
+ // Check to see if the widget size is big enough, if it is return true.
+ public static boolean showList(Context context, int id, float scale) {
+ Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(id);
+ if (options == null) {
+ // no data to make the calculation, show the list anyway
+ return true;
+ }
+ int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
+ int neededSize = (int) context.getResources().
+ getDimension(R.dimen.def_digital_widget_height);
+ return (minHeight > neededSize);
+ }
+}
+
diff --git a/src/com/cyanogenmod/lockclock/misc/Constants.java b/src/com/cyanogenmod/lockclock/misc/Constants.java
new file mode 100644
index 0000000..67ad8f3
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/misc/Constants.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * * Licensed under the GNU GPLv2 license
+ *
+ * The text of the license can be found in the LICENSE file
+ * or at https://www.gnu.org/licenses/gpl-2.0.txt
+ */
+
+package com.cyanogenmod.lockclock.misc;
+
+public class Constants {
+
+ public static final String UPDATE_CHECK_PREF = "pref_update_check";
+ public static final String LAST_UPDATE_CHECK_PREF = "pref_last_update_check";
+
+ // Activity start parameters
+ public static final String CHECK_FOR_UPDATE = "check_for_update";
+ public static final String MANUAL_UPDATE = "manual_update";
+
+ // Update Check items
+ public static final int UPDATE_FREQ_MANUAL = 0;
+ public static final int UPDATE_FREQ_DEFAULT = 10; // Should be 60
+
+}
diff --git a/src/com/cyanogenmod/lockclock/weather/HttpRetriever.java b/src/com/cyanogenmod/lockclock/weather/HttpRetriever.java
new file mode 100644
index 0000000..622fe70
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/weather/HttpRetriever.java
@@ -0,0 +1,152 @@
+/******************************************************************************
+ * Class : HttpConnectHelper.java *
+ * Main Weather activity, in this demo apps i use API from yahoo, you can *
+ * use other weather web service which you prefer *
+ * *
+ * Version : v1.0 *
+ * Date : May 09, 2011 *
+ * Copyright (c)-2011 DatNQ some right reserved *
+ * You can distribute, modify or what ever you want but WITHOUT ANY WARRANTY *
+ * Be honest by keep credit of this file *
+ * *
+ * If you have any concern, feel free to contact with me via email, i will *
+ * check email in free time *
+ * Email: nguyendatnq@gmail.com *
+ * ---------------------------------------------------------------------------*
+ * Modification Logs: *
+ * KEYCHANGE DATE AUTHOR DESCRIPTION *
+ * ---------------------------------------------------------------------------*
+ * ------- May 09, 2011 DatNQ Create new *
+ ******************************************************************************/
+
+/**
+ * Modification into Android-internal HttpRetreiver.java
+ * Copyright (C) 2012 The AOKP Project
+ */
+
+
+package com.cyanogenmod.lockclock.weather;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+
+import android.util.Log;
+
+public class HttpRetriever {
+
+ private final String TAG = getClass().getSimpleName();
+ private DefaultHttpClient client = new DefaultHttpClient();
+ private HttpURLConnection httpConnection;
+
+ public String retrieve(String url) {
+ HttpGet get = new HttpGet(url);
+ try {
+ HttpResponse getResponse = client.execute(get);
+ HttpEntity getResponseEntity = getResponse.getEntity();
+ if (getResponseEntity != null) {
+ String response = EntityUtils.toString(getResponseEntity);
+ return response;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private void requestConnectServer(String strURL) throws IOException {
+ httpConnection = (HttpURLConnection) new URL(strURL).openConnection();
+ httpConnection.connect();
+
+ if (httpConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ Log.e(TAG, "Something wrong with connection");
+ httpConnection.disconnect();
+ throw new IOException("Error in connection: " + httpConnection.getResponseCode());
+ }
+ }
+
+ private void requestDisconnect() {
+ if (httpConnection != null) {
+ httpConnection.disconnect();
+ }
+ }
+
+ public Document getDocumentFromURL(String strURL) throws IOException {
+ if (strURL == null) {
+ Log.e(TAG, "Invalid input URL");
+ return null;
+ }
+
+ // Connect to server, get data and close
+ requestConnectServer(strURL);
+ String strDocContent = getDataFromConnection();
+ requestDisconnect();
+
+ if (strDocContent == null) {
+ Log.e(TAG, "Cannot get XML content");
+ return null;
+ }
+
+ int strContentSize = strDocContent.length();
+ StringBuffer strBuff = new StringBuffer();
+ strBuff.setLength(strContentSize + 1);
+ strBuff.append(strDocContent);
+ ByteArrayInputStream is = new ByteArrayInputStream(strDocContent.getBytes());
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db;
+ Document docData = null;
+
+ try {
+ db = dbf.newDocumentBuilder();
+ docData = db.parse(is);
+ } catch (Exception e) {
+ Log.e(TAG, "Parser data error");
+ return null;
+ }
+ return docData;
+ }
+
+ private String getDataFromConnection() throws IOException {
+ if (httpConnection == null) {
+ Log.e(TAG, "Connection is null");
+ return null;
+ }
+
+ String strValue = null;
+ InputStream inputStream = httpConnection.getInputStream();
+ if (inputStream == null) {
+ Log.e(TAG, "Input stream error");
+ return null;
+ }
+
+ StringBuffer strBuf = new StringBuffer();
+ BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream));
+ String strLine = "";
+
+ while ((strLine = buffReader.readLine()) != null) {
+ strBuf.append(strLine + "\n");
+ strValue += strLine + "\n";
+ }
+
+ // Release resource to system
+ buffReader.close();
+ inputStream.close();
+ return strBuf.toString();
+ }
+}
diff --git a/src/com/cyanogenmod/lockclock/weather/WeatherInfo.java b/src/com/cyanogenmod/lockclock/weather/WeatherInfo.java
new file mode 100644
index 0000000..bb4a5fa
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/weather/WeatherInfo.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 The AOKP 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.cyanogenmod.lockclock.weather;
+
+import android.content.Context;
+import com.cyanogenmod.lockclock.R;
+
+public class WeatherInfo {
+
+ public static final String NODATA = "-";
+
+ public String city, forecast_date, condition, condition_code, temp, temp_unit,
+ humidity, wind, wind_dir, speed_unit, low, high;
+ public long last_sync;
+
+ public WeatherInfo() {
+ this.city = NODATA;
+ this.forecast_date = NODATA;
+ this.condition = NODATA;
+ this.condition_code = NODATA;
+ this.temp = NODATA;
+ this.temp_unit = NODATA;
+ this.humidity = NODATA;
+ this.wind = NODATA;
+ this.wind_dir = NODATA;
+ this.speed_unit = NODATA;
+ this.low = NODATA;
+ this.high = NODATA;
+ this.last_sync = 0;
+ }
+
+ public WeatherInfo(Context context, String city, String fdate, String condition, String condition_code,
+ String temp, String temp_unit, String humidity,
+ String wind, String wind_dir, String speed_unit,
+ String low, String high, long last_sync) {
+ this.city = city;
+ this.forecast_date = fdate;
+ this.condition = condition;
+ this.condition_code = condition_code;
+ this.humidity = humidity + "%";
+ this.wind = calcDirection(context, wind_dir) + " " + trimSpeed(wind) + speed_unit;
+ this.speed_unit = speed_unit;
+ this.last_sync = last_sync;
+ // Only the current temperature gets the temp_unit added.
+ this.temp_unit = temp_unit;
+ this.temp = temp + "°" + temp_unit;
+ this.low = low + "°";
+ this.high = high + "°";
+ }
+
+ /**
+ * find the optimal weather string (helper function for translation)
+ *
+ * @param conditionCode condition code from Yahoo (this is the main
+ * identifier which will be used to find a matching translation
+ * in the project's resources
+ * @param providedString
+ * @return either the defaultString (which should be Yahoo's weather
+ * condition text), or the translated version from resources
+ */
+ public static String getTranslatedConditionString(Context context, int conditionCode,
+ String providedString) {
+ int resID = context.getResources().getIdentifier("weather_" + conditionCode, "string",
+ context.getPackageName());
+ return (resID != 0) ? context.getResources().getString(resID) : providedString;
+ }
+
+ private String calcDirection(Context context, String degrees) {
+ try {
+ int deg = Integer.parseInt(degrees);
+ if (deg >= 338 || deg <= 22)
+ return context.getResources().getString(R.string.weather_N);
+ else if (deg < 68)
+ return context.getResources().getString(R.string.weather_NE);
+ else if (deg < 113)
+ return context.getResources().getString(R.string.weather_E);
+ else if (deg < 158)
+ return context.getResources().getString(R.string.weather_SE);
+ else if (deg < 203)
+ return context.getResources().getString(R.string.weather_S);
+ else if (deg < 248)
+ return context.getResources().getString(R.string.weather_SW);
+ else if (deg < 293)
+ return context.getResources().getString(R.string.weather_W);
+ else if (deg < 338)
+ return context.getResources().getString(R.string.weather_NW);
+ else
+ return "";
+ } catch (NumberFormatException e) {
+ return "";
+ }
+ }
+
+ private String trimSpeed(String speed) {
+ try {
+ return String.valueOf(Math.round(Float.parseFloat(speed)));
+ } catch (NumberFormatException e) {
+ return "";
+ }
+ }
+}
diff --git a/src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java b/src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java
new file mode 100644
index 0000000..50c2c98
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/weather/WeatherXmlParser.java
@@ -0,0 +1,177 @@
+/******************************************************************************
+ * Class : YahooWeatherHelper.java *
+ * Parser helper for Yahoo *
+ * *
+ * Version : v1.0 *
+ * Date : May 06, 2011 *
+ * Copyright (c)-2011 DatNQ some right reserved *
+ * You can distribute, modify or what ever you want but WITHOUT ANY WARRANTY *
+ * Be honest by keep credit of this file *
+ * *
+ * If you have any concern, feel free to contact with me via email, i will *
+ * check email in free time *
+ * Email: nguyendatnq@gmail.com *
+ * ---------------------------------------------------------------------------*
+ * Modification Logs: *
+ * KEYCHANGE DATE AUTHOR DESCRIPTION *
+ * ---------------------------------------------------------------------------*
+ * ------- May 06, 2011 DatNQ Create new *
+ ******************************************************************************/
+/*
+ * Modification into Android-internal WeatherXmlParser.java
+ * Copyright (C) 2012 The AOKP Project
+ */
+
+package com.cyanogenmod.lockclock.weather;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import android.content.Context;
+import android.util.Log;
+
+public class WeatherXmlParser {
+
+ protected static final String TAG = "WeatherXmlParser";
+
+ /** Yahoo attributes */
+ private static final String PARAM_YAHOO_LOCATION = "yweather:location";
+ private static final String PARAM_YAHOO_UNIT = "yweather:units";
+ private static final String PARAM_YAHOO_ATMOSPHERE = "yweather:atmosphere";
+ private static final String PARAM_YAHOO_CONDITION = "yweather:condition";
+ private static final String PARAM_YAHOO_WIND = "yweather:wind";
+ private static final String PARAM_YAHOO_FORECAST = "yweather:forecast";
+
+ private static final String ATT_YAHOO_CITY = "city";
+ private static final String ATT_YAHOO_TEMP = "temp";
+ private static final String ATT_YAHOO_CODE = "code";
+ private static final String ATT_YAHOO_TEMP_UNIT = "temperature";
+ private static final String ATT_YAHOO_HUMIDITY = "humidity";
+ private static final String ATT_YAHOO_TEXT = "text";
+ private static final String ATT_YAHOO_DATE = "date";
+ private static final String ATT_YAHOO_SPEED = "speed";
+ private static final String ATT_YAHOO_DIRECTION = "direction";
+ private static final String ATT_YAHOO_TODAY_HIGH = "high";
+ private static final String ATT_YAHOO_TODAY_LOW = "low";
+
+ private Context mContext;
+
+ public WeatherXmlParser(Context context) {
+ mContext = context;
+ }
+
+ public WeatherInfo parseWeatherResponse(Document docWeather) {
+ if (docWeather == null) {
+ Log.e(TAG, "Invalid doc weather");
+ return null;
+ }
+
+ String strCity = null;
+ String strDate = null;
+ String strCondition = null;
+ String strCondition_code = null;
+ String strTemp = null;
+ String strTempUnit = null;
+ String strHumidity = null;
+ String strWindSpeed = null;
+ String strWindDir = null;
+ String strSpeedUnit = null;
+ String strHigh = null;
+ String strLow = null;
+
+ try {
+ Element root = docWeather.getDocumentElement();
+ root.normalize();
+
+ NamedNodeMap locationNode = root.getElementsByTagName(PARAM_YAHOO_LOCATION).item(0)
+ .getAttributes();
+ if (locationNode != null) {
+ strCity = locationNode.getNamedItem(ATT_YAHOO_CITY).getNodeValue();
+ }
+
+ NamedNodeMap unitNode = root.getElementsByTagName(PARAM_YAHOO_UNIT).item(0)
+ .getAttributes();
+
+ if (locationNode != null) {
+ strTempUnit = unitNode.getNamedItem(ATT_YAHOO_TEMP_UNIT).getNodeValue();
+ strSpeedUnit = unitNode.getNamedItem(ATT_YAHOO_SPEED).getNodeValue();
+ }
+
+ NamedNodeMap atmosNode = root.getElementsByTagName(PARAM_YAHOO_ATMOSPHERE).item(0)
+ .getAttributes();
+ if (atmosNode != null) {
+ strHumidity = atmosNode.getNamedItem(ATT_YAHOO_HUMIDITY).getNodeValue();
+ }
+
+ NamedNodeMap conditionNode = root.getElementsByTagName(PARAM_YAHOO_CONDITION).item(0)
+ .getAttributes();
+ if (conditionNode != null) {
+ strCondition = conditionNode.getNamedItem(ATT_YAHOO_TEXT).getNodeValue();
+ strCondition_code = conditionNode.getNamedItem(ATT_YAHOO_CODE).getNodeValue();
+ strCondition = WeatherInfo.getTranslatedConditionString(mContext, Integer.parseInt(strCondition_code), strCondition);
+ strTemp = conditionNode.getNamedItem(ATT_YAHOO_TEMP).getNodeValue();
+ strDate = conditionNode.getNamedItem(ATT_YAHOO_DATE).getNodeValue();
+ }
+
+ NamedNodeMap temNode = root.getElementsByTagName(PARAM_YAHOO_WIND).item(0)
+ .getAttributes();
+ if (temNode != null) {
+ strWindSpeed = temNode.getNamedItem(ATT_YAHOO_SPEED).getNodeValue();
+ strWindDir = temNode.getNamedItem(ATT_YAHOO_DIRECTION).getNodeValue();
+ }
+
+ NamedNodeMap fcNode = root.getElementsByTagName(PARAM_YAHOO_FORECAST).item(0).getAttributes();
+ if (fcNode != null) {
+ strHigh = fcNode.getNamedItem(ATT_YAHOO_TODAY_HIGH).getNodeValue();
+ strLow = fcNode.getNamedItem(ATT_YAHOO_TODAY_LOW).getNodeValue();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Something wrong with parser data: " + e.toString());
+ return null;
+ }
+
+ /* Weather info */
+ WeatherInfo yahooWeatherInfo = new WeatherInfo(mContext, strCity, strDate, strCondition, strCondition_code, strTemp,
+ strTempUnit, strHumidity, strWindSpeed, strWindDir, strSpeedUnit, strLow, strHigh, System.currentTimeMillis());
+
+ Log.d(TAG, "Weather updated for " + strCity + ": " + strDate + ", " + strCondition + "(" + strCondition_code
+ + "), " + strTemp + strTempUnit + ", " + strHumidity + "% humidity, " + ", wind: " + strWindDir + " at "
+ + strWindSpeed + strSpeedUnit + ", low: " + strLow + strTempUnit + " high: " + strHigh + strTempUnit);
+
+ return yahooWeatherInfo;
+ }
+
+ public String parsePlaceFinderResponse(String response) {
+ try {
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new InputSource(new StringReader(response)));
+
+ NodeList resultNodes = doc.getElementsByTagName("Result");
+
+ Node resultNode = resultNodes.item(0);
+ NodeList attrsList = resultNode.getChildNodes();
+
+ for (int i = 0; i < attrsList.getLength(); i++) {
+ Node node = attrsList.item(i);
+ Node firstChild = node.getFirstChild();
+ if ("woeid".equalsIgnoreCase(node.getNodeName()) && firstChild != null) {
+ return firstChild.getNodeValue();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ return null;
+ }
+}
diff --git a/src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java b/src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java
new file mode 100644
index 0000000..569cef1
--- /dev/null
+++ b/src/com/cyanogenmod/lockclock/weather/YahooPlaceFinder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 The AOKP 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.cyanogenmod.lockclock.weather;
+
+import android.content.Context;
+
+public class YahooPlaceFinder {
+
+ private static final String YAHOO_API_BASE_REV_URL = "http://where.yahooapis.com/geocode?appid=jYkTZp64&q=%1$s,+%2$s&gflags=R";
+ private static final String YAHOO_API_BASE_URL = "http://where.yahooapis.com/geocode?appid=jYkTZp64&q=%1$s";
+
+ public static String reverseGeoCode(Context c, double latitude, double longitude) {
+
+ String url = String.format(YAHOO_API_BASE_REV_URL, String.valueOf(latitude),
+ String.valueOf(longitude));
+ String response = new HttpRetriever().retrieve(url);
+ return new WeatherXmlParser(c).parsePlaceFinderResponse(response);
+
+ }
+
+ public static String GeoCode(Context c, String location) {
+ String url = String.format(YAHOO_API_BASE_URL, location).replace(' ', '+');
+ String response = new HttpRetriever().retrieve(url);
+ return new WeatherXmlParser(c).parsePlaceFinderResponse(response);
+ }
+
+}