From: Daniel Sandler Date: Tue, 27 Oct 2009 20:46:57 +0000 (-0400) Subject: Show weather forecast in DeskClock. X-Git-Tag: android-x86-2.2~36^2^2~49^2 X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fpackages-apps-DeskClock.git;a=commitdiff_plain;h=2763ab4cb6ee8d186eb8894ad006f699bfca3413 Show weather forecast in DeskClock. Currently querying the GenieWidget; if it's not present, no weather is shown or even hinted at in the UI. If GenieWidget is available but fails to respond to the query, we show "Weather unavailable." (needs i18n) Note that Genie's WeatherProvider is currently broken, so for now you'll always see "Weather unavailable." Other changes: - Fix dimming/flashing on rotation. - Fix other layout problems & inefficiencies. --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0a89f0f..fbfce2c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,6 +17,7 @@ android:label="@string/app_label" android:theme="@android:style/Theme.Wallpaper.NoTitleBar" android:icon="@drawable/ic_widget_analog_clock" + android:configChanges="orientation|keyboardHidden|keyboard|navigation"> > diff --git a/res/anim/dim_instant.xml b/res/anim/dim_instant.xml new file mode 100644 index 0000000..bd7fe40 --- /dev/null +++ b/res/anim/dim_instant.xml @@ -0,0 +1,6 @@ + diff --git a/res/anim/undim_instant.xml b/res/anim/undim_instant.xml new file mode 100644 index 0000000..ce20f1e --- /dev/null +++ b/res/anim/undim_instant.xml @@ -0,0 +1,6 @@ + diff --git a/res/layout-land/desk_clock.xml b/res/layout-land/desk_clock.xml index 477c18b..7079975 100644 --- a/res/layout-land/desk_clock.xml +++ b/res/layout-land/desk_clock.xml @@ -36,7 +36,7 @@ android:layout_height="fill_parent" android:layout_marginLeft="20dip" android:layout_marginTop="20dip" - android:layout_marginRight="14dip" + android:layout_marginRight="20dip" android:layout_marginBottom="14dip" > @@ -85,20 +85,20 @@ android:layout_weight="1" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:gravity="center_vertical" + android:gravity="bottom" + android:layout_marginBottom="12dip" > - - + + @@ -114,7 +114,7 @@ diff --git a/res/layout/desk_clock.xml b/res/layout/desk_clock.xml index c688a08..1133275 100644 --- a/res/layout/desk_clock.xml +++ b/res/layout/desk_clock.xml @@ -75,17 +75,18 @@ - - diff --git a/res/layout/desk_clock_time_date.xml b/res/layout/desk_clock_time_date.xml index abd55cf..068d03b 100644 --- a/res/layout/desk_clock_time_date.xml +++ b/res/layout/desk_clock_time_date.xml @@ -16,11 +16,11 @@ @@ -37,7 +37,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" - android:textSize="100sp" + android:textSize="106sp" android:textColor="#FFFFFFFF" android:shadowColor="#C0000000" android:shadowDx="0" @@ -50,7 +50,7 @@ android:layout_width="wrap_content" android:layout_height="fill_parent" android:gravity="bottom" - android:textSize="28sp" + android:textSize="24sp" android:singleLine="true" android:layout_marginLeft="3dip" android:textColor="#FFFFFFFF" diff --git a/res/layout/desk_clock_weather.xml b/res/layout/desk_clock_weather.xml new file mode 100644 index 0000000..bc71b89 --- /dev/null +++ b/res/layout/desk_clock_weather.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + diff --git a/src/com/android/deskclock/DeskClock.java b/src/com/android/deskclock/DeskClock.java index a451372..cb544d3 100644 --- a/src/com/android/deskclock/DeskClock.java +++ b/src/com/android/deskclock/DeskClock.java @@ -24,39 +24,46 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.content.res.Configuration; +import android.content.res.Resources; import android.database.Cursor; -import android.graphics.drawable.Drawable; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; -import android.view.animation.AnimationUtils; -import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; +import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; -import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnCreateContextMenuListener; +import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; -import android.widget.AdapterView; +import android.view.animation.AnimationUtils; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView; import android.widget.Button; -import android.widget.TextView; import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; import static android.os.BatteryManager.BATTERY_STATUS_CHARGING; import static android.os.BatteryManager.BATTERY_STATUS_FULL; import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; +import java.io.IOException; +import java.io.InputStream; import java.text.DateFormat; import java.util.Date; @@ -64,18 +71,54 @@ import java.util.Date; * DeskClock clock view for desk docks. */ public class DeskClock extends Activity { + private static final boolean DEBUG = true; private static final String LOG_TAG = "DeskClock"; private static final String MUSIC_NOW_PLAYING_ACTIVITY = "com.android.music.PLAYBACK_VIEWER"; - private TextView mNextAlarm = null; + private final long FETCH_WEATHER_DELAY = 5 * 60 * 1000; // 5 min. + private final int FETCH_WEATHER_DATA_MSG = 10000; + private final int UPDATE_WEATHER_DISPLAY_MSG = 10001; + + private static final String GENIE_PACKAGE_ID = "com.google.android.apps.genie.geniewidget"; + private static final String WEATHER_CONTENT_AUTHORITY = GENIE_PACKAGE_ID + ".weather"; + private static final String WEATHER_CONTENT_PATH = "/weather/current"; + private static final String[] WEATHER_CONTENT_COLUMNS = new String[] { + "location", + "timestamp", + "highTemperature", + "lowTemperature", + "iconUrl", + "iconResId", + "description", + }; + + private DigitalClock mTime; private TextView mDate; + + private TextView mNextAlarm = null; private TextView mBatteryDisplay; - private DigitalClock mTime; + + private TextView mWeatherTemperature; + private TextView mWeatherLocation; + private ImageView mWeatherIcon; + + private String mWeatherTemperatureString; + private String mWeatherLocationString; + private Drawable mWeatherIconDrawable; + + private Resources mGenieResources = null; private boolean mDimmed = false; + private DateFormat mDateFormat; + + private int mBatteryLevel; + private boolean mPluggedIn; + + private boolean mWeatherFetchScheduled = false; + private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -90,10 +133,95 @@ public class DeskClock extends Activity { } }; - private DateFormat mDateFormat; - - private int mBatteryLevel; - private boolean mPluggedIn; + private final Handler mHandy = new Handler() { + @Override + public void handleMessage(Message m) { + if (DEBUG) Log.d(LOG_TAG, "handleMessage: " + m.toString()); + + if (m.what == FETCH_WEATHER_DATA_MSG) { + if (!mWeatherFetchScheduled) return; + mWeatherFetchScheduled = false; + new Thread() { public void run() { fetchWeatherData(); } }.start(); + scheduleWeatherFetchDelayed(FETCH_WEATHER_DELAY); + } else if (m.what == UPDATE_WEATHER_DISPLAY_MSG) { + updateWeatherDisplay(); + } + } + }; + + private boolean supportsWeather() { + return (mGenieResources != null); + } + + private void scheduleWeatherFetchDelayed(long delay) { + if (mWeatherFetchScheduled) return; + + if (DEBUG) Log.d(LOG_TAG, "scheduling weather fetch message for " + delay + "ms from now"); + + mWeatherFetchScheduled = true; + + mHandy.sendEmptyMessageDelayed(FETCH_WEATHER_DATA_MSG, delay); + } + + private void unscheduleWeatherFetch() { + mWeatherFetchScheduled = false; + } + + private void fetchWeatherData() { + // if we couldn't load the weather widget's resources, we simply + // assume it's not present on the device. + if (mGenieResources == null) return; + + Uri queryUri = new Uri.Builder() + .scheme(android.content.ContentResolver.SCHEME_CONTENT) + .authority(WEATHER_CONTENT_AUTHORITY) + .path(WEATHER_CONTENT_PATH) + .appendPath(new Long(System.currentTimeMillis()).toString()) + .build(); + + if (DEBUG) Log.d(LOG_TAG, "querying genie: " + queryUri); + + Cursor cur; + try { + cur = managedQuery( + queryUri, + WEATHER_CONTENT_COLUMNS, + null, + null, + null); + } catch (RuntimeException e) { + Log.e(LOG_TAG, "Weather query failed", e); + cur = null; + } + + if (cur != null && cur.moveToFirst()) { + mWeatherIconDrawable = mGenieResources.getDrawable(cur.getInt( + cur.getColumnIndexOrThrow("iconResId"))); + mWeatherTemperatureString = cur.getString( + cur.getColumnIndexOrThrow("highTemperature")); + mWeatherLocationString = cur.getString( + cur.getColumnIndexOrThrow("location")); + } else { + Log.w(LOG_TAG, "No weather information available (cur=" + + cur +")"); + mWeatherIconDrawable = null; + mWeatherTemperatureString = ""; + mWeatherLocationString = "Weather data unavailable."; // TODO: internationalize + } + + mHandy.sendEmptyMessage(UPDATE_WEATHER_DISPLAY_MSG); + } + + private void refreshWeather() { + if (supportsWeather()) + scheduleWeatherFetchDelayed(0); + } + + private void updateWeatherDisplay() { + mWeatherTemperature.setText(mWeatherTemperatureString); + mWeatherLocation.setText(mWeatherLocationString); + mWeatherIcon.setImageDrawable(mWeatherIconDrawable); + } // Adapted from KeyguardUpdateMonitor.java private void handleBatteryUpdate(int plugStatus, int batteryLevel) { @@ -134,7 +262,14 @@ public class DeskClock extends Activity { } } - private void doDim() { + private void refreshAll() { + refreshDate(); + refreshAlarm(); + refreshBattery(); + refreshWeather(); + } + + private void doDim(boolean fade) { View tintView = findViewById(R.id.window_tint); Window win = getWindow(); @@ -149,14 +284,18 @@ public class DeskClock extends Activity { winParams.dimAmount = 0.5f; // pump up contrast in dim mode // show the window tint - tintView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.dim)); + tintView.startAnimation(AnimationUtils.loadAnimation(this, + fade ? R.anim.dim + : R.anim.dim_instant)); } else { winParams.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); // winParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; winParams.dimAmount = 0.2f; // lower contrast in normal mode // hide the window tint - tintView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.undim)); + tintView.startAnimation(AnimationUtils.loadAnimation(this, + fade ? R.anim.undim + : R.anim.undim_instant)); } win.setAttributes(winParams); @@ -175,16 +314,15 @@ public class DeskClock extends Activity { filter.addAction(Intent.ACTION_BATTERY_CHANGED); registerReceiver(mIntentReceiver, filter); - doDim(); - refreshDate(); - refreshAlarm(); - refreshBattery(); + doDim(false); + refreshAll(); } @Override public void onPause() { super.onPause(); unregisterReceiver(mIntentReceiver); + unscheduleWeatherFetch(); } @@ -195,6 +333,10 @@ public class DeskClock extends Activity { mDate = (TextView) findViewById(R.id.date); mBatteryDisplay = (TextView) findViewById(R.id.battery); + mWeatherTemperature = (TextView) findViewById(R.id.weather_temperature); + mWeatherLocation = (TextView) findViewById(R.id.weather_location); + mWeatherIcon = (ImageView) findViewById(R.id.weather_icon); + mNextAlarm = (TextView) findViewById(R.id.nextAlarm); final Button alarmButton = (Button) findViewById(R.id.alarm_button); @@ -241,23 +383,30 @@ public class DeskClock extends Activity { nightmodeButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mDimmed = ! mDimmed; - doDim(); + doDim(true); } }); - - doDim(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); initViews(); + doDim(false); + refreshAll(); } - @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); + + try { + mGenieResources = getPackageManager().getResourcesForApplication(GENIE_PACKAGE_ID); + } catch (PackageManager.NameNotFoundException e) { + // no weather info available + Log.w(LOG_TAG, "Can't find "+GENIE_PACKAGE_ID+". Weather forecast will not be available."); + } + initViews(); }