Initial commit
This commit is contained in:
commit
5cd4c6ca0c
24
AndroidManifest.xml
Normal file
24
AndroidManifest.xml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.annimon.screenweather"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0" >
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme" >
|
||||||
|
<activity
|
||||||
|
android:name="WeatherListActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity android:name="ShowWeatherActivity" />
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
19
ant.properties
Normal file
19
ant.properties
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# This file is used to override default values used by the Ant build system.
|
||||||
|
#
|
||||||
|
# This file must be checked into Version Control Systems, as it is
|
||||||
|
# integral to the build system of your project.
|
||||||
|
|
||||||
|
# This file is only used by the Ant script.
|
||||||
|
|
||||||
|
# You can use this to override default values such as
|
||||||
|
# 'source.dir' for the location of your java source folder and
|
||||||
|
# 'out.dir' for the location of your output folder.
|
||||||
|
|
||||||
|
# You can also use it define how the release builds are signed by declaring
|
||||||
|
# the following properties:
|
||||||
|
# 'key.store' for the location of your keystore and
|
||||||
|
# 'key.alias' for the name of the key to use.
|
||||||
|
# The password will be asked during the build when you use the 'release' target.
|
||||||
|
|
||||||
|
key.store=C:\\Android\\android-sign\\keystore
|
||||||
|
key.alias=sign
|
92
build.xml
Normal file
92
build.xml
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="ScreenWeather" default="help">
|
||||||
|
|
||||||
|
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||||
|
It contains the path to the SDK. It should *NOT* be checked into
|
||||||
|
Version Control Systems. -->
|
||||||
|
<property file="local.properties" />
|
||||||
|
|
||||||
|
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||||
|
'android' tool to add properties to it.
|
||||||
|
This is the place to change some Ant specific build properties.
|
||||||
|
Here are some properties you may want to change/update:
|
||||||
|
|
||||||
|
source.dir
|
||||||
|
The name of the source directory. Default is 'src'.
|
||||||
|
out.dir
|
||||||
|
The name of the output directory. Default is 'bin'.
|
||||||
|
|
||||||
|
For other overridable properties, look at the beginning of the rules
|
||||||
|
files in the SDK, at tools/ant/build.xml
|
||||||
|
|
||||||
|
Properties related to the SDK location or the project target should
|
||||||
|
be updated using the 'android' tool with the 'update' action.
|
||||||
|
|
||||||
|
This file is an integral part of the build system for your
|
||||||
|
application and should be checked into Version Control Systems.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<property file="ant.properties" />
|
||||||
|
|
||||||
|
<!-- if sdk.dir was not set from one of the property file, then
|
||||||
|
get it from the ANDROID_HOME env var.
|
||||||
|
This must be done before we load project.properties since
|
||||||
|
the proguard config can use sdk.dir -->
|
||||||
|
<property environment="env" />
|
||||||
|
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||||
|
<isset property="env.ANDROID_HOME" />
|
||||||
|
</condition>
|
||||||
|
|
||||||
|
<!-- The project.properties file is created and updated by the 'android'
|
||||||
|
tool, as well as ADT.
|
||||||
|
|
||||||
|
This contains project specific properties such as project target, and library
|
||||||
|
dependencies. Lower level build properties are stored in ant.properties
|
||||||
|
(or in .classpath for Eclipse projects).
|
||||||
|
|
||||||
|
This file is an integral part of the build system for your
|
||||||
|
application and should be checked into Version Control Systems. -->
|
||||||
|
<loadproperties srcFile="project.properties" />
|
||||||
|
|
||||||
|
<!-- quick check on sdk.dir -->
|
||||||
|
<fail
|
||||||
|
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||||
|
unless="sdk.dir"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Import per project custom build rules if present at the root of the project.
|
||||||
|
This is the place to put custom intermediary targets such as:
|
||||||
|
-pre-build
|
||||||
|
-pre-compile
|
||||||
|
-post-compile (This is typically used for code obfuscation.
|
||||||
|
Compiled code location: ${out.classes.absolute.dir}
|
||||||
|
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||||
|
-post-package
|
||||||
|
-post-build
|
||||||
|
-pre-clean
|
||||||
|
-->
|
||||||
|
<import file="custom_rules.xml" optional="true" />
|
||||||
|
|
||||||
|
<!-- Import the actual build file.
|
||||||
|
|
||||||
|
To customize existing targets, there are two options:
|
||||||
|
- Customize only one target:
|
||||||
|
- copy/paste the target into this file, *before* the
|
||||||
|
<import> task.
|
||||||
|
- customize it to your needs.
|
||||||
|
- Customize the whole content of build.xml
|
||||||
|
- copy/paste the content of the rules files (minus the top node)
|
||||||
|
into this file, replacing the <import> task.
|
||||||
|
- customize to your needs.
|
||||||
|
|
||||||
|
***********************
|
||||||
|
****** IMPORTANT ******
|
||||||
|
***********************
|
||||||
|
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||||
|
in order to avoid having your file be overridden by tools such as "android update project"
|
||||||
|
-->
|
||||||
|
<!-- version-tag: 1 -->
|
||||||
|
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||||
|
|
||||||
|
</project>
|
10
local.properties
Normal file
10
local.properties
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must *NOT* be checked into Version Control Systems,
|
||||||
|
# as it contains information specific to your local configuration.
|
||||||
|
|
||||||
|
# location of the SDK. This is only used by Ant
|
||||||
|
# For customization when using a Version Control System, please read the
|
||||||
|
# header note.
|
||||||
|
sdk.dir=D:\\Android\\android-sdk
|
26
proguard-project.txt
Normal file
26
proguard-project.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# To enable ProGuard in your project, edit project.properties
|
||||||
|
# to define the proguard.config property as described in that file.
|
||||||
|
#
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the ProGuard
|
||||||
|
# include property in project.properties.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
-obfuscationdictionary E:\SETUPS\Disk\Programming\Java\compact.txt
|
||||||
|
-optimizationpasses 9
|
||||||
|
-printmapping <user.home>\Documents\NetBeansProjects\map.txt
|
||||||
|
-printusage <user.home>\Documents\NetBeansProjects\usage.txt
|
||||||
|
# -dontusemixedcaseclassnames
|
||||||
|
# -repackageclasses ''
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
14
project.properties
Normal file
14
project.properties
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system edit
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
#
|
||||||
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
|
proguard.config=${sdk.dir}\\tools\\proguard\\proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-16
|
BIN
res/drawable-hdpi/ic_launcher.png
Normal file
BIN
res/drawable-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
res/drawable-ldpi/ic_launcher.png
Normal file
BIN
res/drawable-ldpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
res/drawable-mdpi/ic_launcher.png
Normal file
BIN
res/drawable-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
res/drawable-xhdpi/ic_launcher.png
Normal file
BIN
res/drawable-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
29
res/layout/main.xml
Normal file
29
res/layout/main.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.annimon.screenweather.AnimationLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/animation_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@id/animation_layout_sidebar"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/weathersListView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- To make LinearLayout clickable to trigger onContentTouchedWhenOpening() -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@id/animation_layout_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clickable="true"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/content_image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</LinearLayout>
|
||||||
|
</com.annimon.screenweather.AnimationLayout>
|
59
res/layout/ololo.xml
Normal file
59
res/layout/ololo.xml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cityTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:text="City"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textSize="20dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currentTemperatureTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_below="@+id/cityTextView"
|
||||||
|
android:text="20 ^C"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="25dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/windInfoTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_below="@+id/currentTemperatureTextView"
|
||||||
|
android:text="Wind: 16 km/h, West"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/summaryInfoTextView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_below="@+id/windInfoTextView"
|
||||||
|
android:text="Summary"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:id="@+id/horizontalScrollView1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_centerVertical="true" >
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
</LinearLayout>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
73
res/layout/show_weather.xml
Normal file
73
res/layout/show_weather.xml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cityLabel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currentWind"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="left"
|
||||||
|
android:textSize="25sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currentTemp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="50sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/currentHumidity"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="right"
|
||||||
|
android:textSize="25sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/summary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="italic" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dayInfo1"
|
||||||
|
style="@style/day_info_style" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dayInfo2"
|
||||||
|
style="@style/day_info_style" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dayInfo3"
|
||||||
|
style="@style/day_info_style" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dayInfo4"
|
||||||
|
style="@style/day_info_style" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
5
res/values-v11/styles.xml
Normal file
5
res/values-v11/styles.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="AppTheme" parent="android:Theme.Holo.Light" />
|
||||||
|
|
||||||
|
</resources>
|
5
res/values-v14/styles.xml
Normal file
5
res/values-v14/styles.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
|
||||||
|
|
||||||
|
</resources>
|
9
res/values/day_info_style.xml
Normal file
9
res/values/day_info_style.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="day_info_style">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:textSize">16sp</item>
|
||||||
|
<item name="android:layout_marginTop">10dp</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
5
res/values/ids.xml
Normal file
5
res/values/ids.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<item type="id" name="animation_layout_sidebar" />
|
||||||
|
<item type="id" name="animation_layout_content" />
|
||||||
|
</resources>
|
6
res/values/strings.xml
Normal file
6
res/values/strings.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Screen Weather</string>
|
||||||
|
<string name="please_wait">Please wait</string>
|
||||||
|
<string name="close">Close</string>
|
||||||
|
</resources>
|
5
res/values/styles.xml
Normal file
5
res/values/styles.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="AppTheme" parent="android:Theme.Light" />
|
||||||
|
|
||||||
|
</resources>
|
263
src/com/annimon/screenweather/AnimationLayout.java
Normal file
263
src/com/annimon/screenweather/AnimationLayout.java
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
package com.annimon.screenweather;
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 0xlab - http://0xlab.org/
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Authored by Julian Chu <walkingice AT 0xlab.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// update the package name to match your app
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.TranslateAnimation;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.MeasureSpec;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
|
|
||||||
|
public class AnimationLayout extends ViewGroup {
|
||||||
|
|
||||||
|
public final static int DURATION = 500;
|
||||||
|
|
||||||
|
protected boolean mPlaceLeft = true;
|
||||||
|
protected boolean mOpened;
|
||||||
|
protected View mSidebar;
|
||||||
|
protected View mContent;
|
||||||
|
protected int mSidebarWidth = 150; /* assign default value. It will be overwrite
|
||||||
|
in onMeasure by Layout xml resource. */
|
||||||
|
|
||||||
|
protected Animation mAnimation;
|
||||||
|
protected OpenListener mOpenListener;
|
||||||
|
protected CloseListener mCloseListener;
|
||||||
|
protected Listener mListener;
|
||||||
|
|
||||||
|
protected boolean mPressed = false;
|
||||||
|
|
||||||
|
public AnimationLayout(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimationLayout(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
mSidebar = findViewById(R.id.animation_layout_sidebar);
|
||||||
|
mContent = findViewById(R.id.animation_layout_content);
|
||||||
|
|
||||||
|
if (mSidebar == null) {
|
||||||
|
throw new NullPointerException("no view id = animation_sidebar");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mContent == null) {
|
||||||
|
throw new NullPointerException("no view id = animation_content");
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenListener = new OpenListener(mSidebar, mContent);
|
||||||
|
mCloseListener = new CloseListener(mSidebar, mContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
|
/* the title bar assign top padding, drop it */
|
||||||
|
int sidebarLeft = l;
|
||||||
|
if (!mPlaceLeft) {
|
||||||
|
sidebarLeft = r - mSidebarWidth;
|
||||||
|
}
|
||||||
|
mSidebar.layout(sidebarLeft,
|
||||||
|
0,
|
||||||
|
sidebarLeft + mSidebarWidth,
|
||||||
|
0 + mSidebar.getMeasuredHeight());
|
||||||
|
|
||||||
|
if (mOpened) {
|
||||||
|
if (mPlaceLeft) {
|
||||||
|
mContent.layout(l + mSidebarWidth, 0, r + mSidebarWidth, b);
|
||||||
|
} else {
|
||||||
|
mContent.layout(l - mSidebarWidth, 0, r - mSidebarWidth, b);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mContent.layout(l, 0, r, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMeasure(int w, int h) {
|
||||||
|
super.onMeasure(w, h);
|
||||||
|
super.measureChildren(w, h);
|
||||||
|
mSidebarWidth = mSidebar.getMeasuredWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void measureChild(View child, int parentWSpec, int parentHSpec) {
|
||||||
|
/* the max width of Sidebar is 90% of Parent */
|
||||||
|
if (child == mSidebar) {
|
||||||
|
int mode = MeasureSpec.getMode(parentWSpec);
|
||||||
|
int width = (int)(getMeasuredWidth() * 0.9);
|
||||||
|
super.measureChild(child, MeasureSpec.makeMeasureSpec(width, mode), parentHSpec);
|
||||||
|
} else {
|
||||||
|
super.measureChild(child, parentWSpec, parentHSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
if (!isOpening()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int action = ev.getAction();
|
||||||
|
|
||||||
|
if (action != MotionEvent.ACTION_UP
|
||||||
|
&& action != MotionEvent.ACTION_DOWN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if user press and release both on Content while
|
||||||
|
* sidebar is opening, call listener. otherwise, pass
|
||||||
|
* the event to child. */
|
||||||
|
int x = (int)ev.getX();
|
||||||
|
int y = (int)ev.getY();
|
||||||
|
if (mContent.getLeft() < x
|
||||||
|
&& mContent.getRight() > x
|
||||||
|
&& mContent.getTop() < y
|
||||||
|
&& mContent.getBottom() > y) {
|
||||||
|
if (action == MotionEvent.ACTION_DOWN) {
|
||||||
|
mPressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPressed
|
||||||
|
&& action == MotionEvent.ACTION_UP
|
||||||
|
&& mListener != null) {
|
||||||
|
mPressed = false;
|
||||||
|
return mListener.onContentTouchedWhenOpening();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mPressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListener(Listener l) {
|
||||||
|
mListener = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to see if the Sidebar is visible */
|
||||||
|
public boolean isOpening() {
|
||||||
|
return mOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleSidebar() {
|
||||||
|
if (mContent.getAnimation() != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mOpened) {
|
||||||
|
/* opened, make close animation*/
|
||||||
|
if (mPlaceLeft) {
|
||||||
|
mAnimation = new TranslateAnimation(0, -mSidebarWidth, 0, 0);
|
||||||
|
} else {
|
||||||
|
mAnimation = new TranslateAnimation(0, mSidebarWidth, 0, 0);
|
||||||
|
}
|
||||||
|
mAnimation.setAnimationListener(mCloseListener);
|
||||||
|
} else {
|
||||||
|
/* not opened, make open animation */
|
||||||
|
if (mPlaceLeft) {
|
||||||
|
mAnimation = new TranslateAnimation(0, mSidebarWidth, 0, 0);
|
||||||
|
} else {
|
||||||
|
mAnimation = new TranslateAnimation(0, -mSidebarWidth, 0, 0);
|
||||||
|
}
|
||||||
|
mAnimation.setAnimationListener(mOpenListener);
|
||||||
|
}
|
||||||
|
mAnimation.setDuration(DURATION);
|
||||||
|
mAnimation.setFillAfter(true);
|
||||||
|
mAnimation.setFillEnabled(true);
|
||||||
|
mContent.startAnimation(mAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openSidebar() {
|
||||||
|
if (!mOpened) {
|
||||||
|
toggleSidebar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeSidebar() {
|
||||||
|
if (mOpened) {
|
||||||
|
toggleSidebar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OpenListener implements Animation.AnimationListener {
|
||||||
|
View iSidebar;
|
||||||
|
View iContent;
|
||||||
|
|
||||||
|
OpenListener(View sidebar, View content) {
|
||||||
|
iSidebar = sidebar;
|
||||||
|
iContent = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationRepeat(Animation animation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationStart(Animation animation) {
|
||||||
|
iSidebar.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationEnd(Animation animation) {
|
||||||
|
iContent.clearAnimation();
|
||||||
|
mOpened = !mOpened;
|
||||||
|
requestLayout();
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onSidebarOpened();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CloseListener implements Animation.AnimationListener {
|
||||||
|
View iSidebar;
|
||||||
|
View iContent;
|
||||||
|
|
||||||
|
CloseListener(View sidebar, View content) {
|
||||||
|
iSidebar = sidebar;
|
||||||
|
iContent = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationRepeat(Animation animation) {
|
||||||
|
}
|
||||||
|
public void onAnimationStart(Animation animation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationEnd(Animation animation) {
|
||||||
|
iContent.clearAnimation();
|
||||||
|
iSidebar.setVisibility(View.INVISIBLE);
|
||||||
|
mOpened = !mOpened;
|
||||||
|
requestLayout();
|
||||||
|
if (mListener != null) {
|
||||||
|
mListener.onSidebarClosed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
public void onSidebarOpened();
|
||||||
|
public void onSidebarClosed();
|
||||||
|
public boolean onContentTouchedWhenOpening();
|
||||||
|
}
|
||||||
|
}
|
104
src/com/annimon/screenweather/CurrentCondition.java
Normal file
104
src/com/annimon/screenweather/CurrentCondition.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* aNNiMON 2012
|
||||||
|
* For more info visit http://annimon.com/
|
||||||
|
*/
|
||||||
|
package com.annimon.screenweather;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Информация о текущем состоянии погоды.
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class CurrentCondition {
|
||||||
|
|
||||||
|
/** Картинка погоды. */
|
||||||
|
private Bitmap icon;
|
||||||
|
/** Общие сведения о погоде. */
|
||||||
|
private String summary;
|
||||||
|
/** Температура воздуха. */
|
||||||
|
protected String temperature;
|
||||||
|
/** Влажность воздуха. */
|
||||||
|
private String humidity;
|
||||||
|
/** Состояние ветра. */
|
||||||
|
private Wind windInfo;
|
||||||
|
|
||||||
|
public CurrentCondition() {
|
||||||
|
icon = null;
|
||||||
|
summary = temperature = humidity = "NULL";
|
||||||
|
windInfo = new Wind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder currTemp = new StringBuilder();
|
||||||
|
currTemp.append("Ветер: ").append(windInfo.toString()).append('\n');
|
||||||
|
currTemp.append("Влажность: ").append(humidity).append('\n');
|
||||||
|
currTemp.append(summary);
|
||||||
|
|
||||||
|
return currTemp.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//<editor-fold defaultstate="collapsed" desc="Get/Set">
|
||||||
|
public Bitmap getIcon() {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcon(Bitmap icon) {
|
||||||
|
this.icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSummary() {
|
||||||
|
if (summary.equals("NULL")) return "";
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSummary(String summary) {
|
||||||
|
if (summary.isEmpty()) return;
|
||||||
|
char[] summaryChars = summary.trim().toCharArray();
|
||||||
|
summaryChars[0] = Character.toUpperCase(summaryChars[0]);
|
||||||
|
this.summary = String.valueOf(summaryChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemperature() {
|
||||||
|
if (temperature.equals("NULL")) return "";
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemperature(String value) {
|
||||||
|
temperature = value.trim();
|
||||||
|
if (!temperature.endsWith("°C")) {
|
||||||
|
temperature = temperature + "°C";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHumidity() {
|
||||||
|
if (humidity.equals("NULL")) return "";
|
||||||
|
return humidity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHumidity(String value) {
|
||||||
|
humidity = value.trim();
|
||||||
|
// Удаляем нечисловые символы.
|
||||||
|
while (!Character.isDigit(humidity.charAt(0))) {
|
||||||
|
humidity = humidity.substring(1);
|
||||||
|
}
|
||||||
|
// Нормализируем знак процента.
|
||||||
|
if (humidity.endsWith("%")) {
|
||||||
|
humidity = humidity.replace('%', ' ');
|
||||||
|
humidity = humidity.trim();
|
||||||
|
}
|
||||||
|
humidity = humidity + "%";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Wind getWindInfo() {
|
||||||
|
return windInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWindInfo(Wind windInfo) {
|
||||||
|
this.windInfo = windInfo;
|
||||||
|
}
|
||||||
|
//</editor-fold>
|
||||||
|
|
||||||
|
}
|
64
src/com/annimon/screenweather/DayInfo.java
Normal file
64
src/com/annimon/screenweather/DayInfo.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* aNNiMON 2012
|
||||||
|
* For more info visit http://annimon.com/
|
||||||
|
*/
|
||||||
|
package com.annimon.screenweather;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Прогноз погоды на день.
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class DayInfo extends CurrentCondition {
|
||||||
|
|
||||||
|
private String temperatureMax;
|
||||||
|
|
||||||
|
public DayInfo() {
|
||||||
|
super();
|
||||||
|
temperature = temperatureMax = "NULL";
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Получить минимальную температуру воздуха.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getTemperature() {
|
||||||
|
if (temperature.equals("NULL")) return "--";
|
||||||
|
return temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Установить минимальную температуру воздуха.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setTemperature(String value) {
|
||||||
|
// StringBuilder temp = new StringBuilder(value);
|
||||||
|
// while(!Character.isDigit(temp.charAt(temp.length() - 1))) {
|
||||||
|
// temp.deleteCharAt(temp.length() - 1);
|
||||||
|
// }
|
||||||
|
temperature = value.trim();
|
||||||
|
|
||||||
|
while(!Character.isDigit(temperature.charAt(temperature.length() - 1))) {
|
||||||
|
temperature = temperature.substring(0, temperature.length() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemperatureMax() {
|
||||||
|
if (temperatureMax.equals("NULL")) return "--";
|
||||||
|
return temperatureMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemperatureMax(String value) {
|
||||||
|
temperatureMax = value.trim();
|
||||||
|
if (!temperature.endsWith("°C")) {
|
||||||
|
temperature = temperature + "°C";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(temperature).append(" / ").append(temperatureMax).append("°C\n");
|
||||||
|
sb.append(getSummary());
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
123
src/com/annimon/screenweather/ShowWeatherActivity.java
Normal file
123
src/com/annimon/screenweather/ShowWeatherActivity.java
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* aNNiMON 2012
|
||||||
|
* For more info visit http://annimon.com/
|
||||||
|
*/
|
||||||
|
package com.annimon.screenweather;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.ProgressDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import com.annimon.screenweather.weather.WUnderground;
|
||||||
|
import com.annimon.screenweather.weather.Weather;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class ShowWeatherActivity extends Activity {
|
||||||
|
|
||||||
|
private static final int DAYS_COUNT = 3;
|
||||||
|
|
||||||
|
private static Handler handler;
|
||||||
|
private ProgressDialog progress;
|
||||||
|
private Weather weather;
|
||||||
|
|
||||||
|
private TextView cityLabel, currentWind, currentTemp, currentHumidity, summary;
|
||||||
|
private TextView[] dayInfo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle icicle) {
|
||||||
|
super.onCreate(icicle);
|
||||||
|
setContentView(R.layout.show_weather);
|
||||||
|
getWidgets();
|
||||||
|
setWeatherService();
|
||||||
|
createDialog();
|
||||||
|
try {
|
||||||
|
setHandler();
|
||||||
|
updateInfo();
|
||||||
|
} catch (Exception e) {
|
||||||
|
createAlertDialog(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setWeatherService() {
|
||||||
|
int position = getIntent().getExtras().getInt("position", 0);
|
||||||
|
switch(position) {
|
||||||
|
case 0: weather = new WUnderground(); break;
|
||||||
|
}
|
||||||
|
setTitle(getIntent().getExtras().getString("title"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInfo() {
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
weather.updateInfo(DAYS_COUNT);
|
||||||
|
Message msg = handler.obtainMessage(1);
|
||||||
|
handler.sendMessage(msg);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setHandler() {
|
||||||
|
handler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
if (msg.what == 1) {
|
||||||
|
progress.dismiss();
|
||||||
|
Log.d(getClass().getName(), weather.getCurrentCondition().toString(), null);
|
||||||
|
cityLabel.setText(weather.getCity());
|
||||||
|
CurrentCondition condition = weather.getCurrentCondition();
|
||||||
|
currentWind.setText(condition.getWindInfo().toString());
|
||||||
|
currentTemp.setText(condition.getTemperature());
|
||||||
|
currentHumidity.setText(condition.getHumidity());
|
||||||
|
for (int i = 0; i < weather.getDaysCount(); i++) {
|
||||||
|
DayInfo info = weather.getDayInfo(i);
|
||||||
|
dayInfo[i].setText(info.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//final TextView tTemper = (TextView) findViewById(R.id.textviewTemperature);
|
||||||
|
//tTemper.setText((String) msg.obj + "°"); // отображение температуры
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDialog() {
|
||||||
|
progress = new ProgressDialog(this);
|
||||||
|
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
|
||||||
|
progress.setMessage(getText(R.string.please_wait));
|
||||||
|
progress.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createAlertDialog(String message) {
|
||||||
|
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||||
|
alert.setMessage(message);
|
||||||
|
alert.setNegativeButton(R.string.close, new DialogInterface.OnClickListener() {
|
||||||
|
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
alert.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getWidgets() {
|
||||||
|
cityLabel = (TextView) findViewById(R.id.cityLabel);
|
||||||
|
currentWind = (TextView) findViewById(R.id.currentWind);
|
||||||
|
currentTemp = (TextView) findViewById(R.id.currentTemp);
|
||||||
|
currentHumidity = (TextView) findViewById(R.id.currentHumidity);
|
||||||
|
summary = (TextView) findViewById(R.id.summary);
|
||||||
|
dayInfo = new TextView[] {
|
||||||
|
(TextView) findViewById(R.id.dayInfo1),
|
||||||
|
(TextView) findViewById(R.id.dayInfo2),
|
||||||
|
(TextView) findViewById(R.id.dayInfo3),
|
||||||
|
(TextView) findViewById(R.id.dayInfo4)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
src/com/annimon/screenweather/StringEncoder.java
Normal file
35
src/com/annimon/screenweather/StringEncoder.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* aNNiMON 2012
|
||||||
|
* For more info visit http://annimon.com/
|
||||||
|
*/
|
||||||
|
package com.annimon.screenweather;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class StringEncoder {
|
||||||
|
private static char[] cp1251 = {
|
||||||
|
'\u0410', '\u0411', '\u0412', '\u0413', '\u0414', '\u0415', '\u0416',
|
||||||
|
'\u0417', '\u0418', '\u0419', '\u041A', '\u041B', '\u041C', '\u041D',
|
||||||
|
'\u041E', '\u041F', '\u0420', '\u0421', '\u0422', '\u0423', '\u0424',
|
||||||
|
'\u0425', '\u0426', '\u0427', '\u0428', '\u0429', '\u042A', '\u042B',
|
||||||
|
'\u042C', '\u042D', '\u042E', '\u042F', '\u0430', '\u0431', '\u0432',
|
||||||
|
'\u0433', '\u0434', '\u0435', '\u0436', '\u0437', '\u0438', '\u0439',
|
||||||
|
'\u043A', '\u043B', '\u043C', '\u043D', '\u043E', '\u043F', '\u0440',
|
||||||
|
'\u0441', '\u0442', '\u0443', '\u0444', '\u0445', '\u0446', '\u0447',
|
||||||
|
'\u0448', '\u0449', '\u044A', '\u044B', '\u044C', '\u044D', '\u044E',
|
||||||
|
'\u044F'
|
||||||
|
};
|
||||||
|
|
||||||
|
public static char decodeCharCP1251 (int b) {
|
||||||
|
int ich = b & 0xff;
|
||||||
|
if (ich == 0xb8) // ё
|
||||||
|
return 0x0451;
|
||||||
|
else if (ich == 0xa8) // Ё
|
||||||
|
return 0x0401;
|
||||||
|
else if (ich >= 0xc0)
|
||||||
|
return cp1251[ich-192];
|
||||||
|
return (char)ich;
|
||||||
|
}
|
||||||
|
}
|
36
src/com/annimon/screenweather/WeatherListActivity.java
Normal file
36
src/com/annimon/screenweather/WeatherListActivity.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package com.annimon.screenweather;
|
||||||
|
|
||||||
|
import android.app.ListActivity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class WeatherListActivity extends ListActivity implements AdapterView.OnItemClickListener {
|
||||||
|
|
||||||
|
private static final String[] WEATHER_LIST = {
|
||||||
|
"WUnderground"
|
||||||
|
};
|
||||||
|
|
||||||
|
private ArrayAdapter<String> adapter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, WEATHER_LIST);
|
||||||
|
setListAdapter(adapter);
|
||||||
|
getListView().setOnItemClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
Intent intent = new Intent(getApplicationContext(), ShowWeatherActivity.class);
|
||||||
|
intent.putExtra("position", position);
|
||||||
|
intent.putExtra("title", parent.getItemAtPosition(position).toString());
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
47
src/com/annimon/screenweather/Wind.java
Normal file
47
src/com/annimon/screenweather/Wind.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* aNNiMON 2012
|
||||||
|
* For more info visit http://annimon.com/
|
||||||
|
*/
|
||||||
|
package com.annimon.screenweather;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class Wind {
|
||||||
|
|
||||||
|
/** Скорость ветра. */
|
||||||
|
private String speed;
|
||||||
|
/** Направление ветра. */
|
||||||
|
private String direction;
|
||||||
|
|
||||||
|
public Wind() {
|
||||||
|
speed = direction = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpeed(String speed) {
|
||||||
|
this.speed = speed.trim();
|
||||||
|
// Удаляем нечисловые символы.
|
||||||
|
while (!Character.isDigit(this.speed.charAt(0))) {
|
||||||
|
this.speed = this.speed.substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirection(String dir) {
|
||||||
|
this.direction = " " + toRussian(dir.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (speed.length() == 0) return direction;
|
||||||
|
return (speed + direction).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toRussian(String str) {
|
||||||
|
return str.replace('N', 'С').
|
||||||
|
replace('S', 'Ю').
|
||||||
|
replace('E', 'В').
|
||||||
|
replace('W', 'З');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
155
src/com/annimon/screenweather/weather/WUnderground.java
Normal file
155
src/com/annimon/screenweather/weather/WUnderground.java
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* aNNiMON 2012
|
||||||
|
* For more info visit http://annimon.com/
|
||||||
|
*/
|
||||||
|
package com.annimon.screenweather.weather;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import com.annimon.screenweather.CurrentCondition;
|
||||||
|
import com.annimon.screenweather.DayInfo;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public class WUnderground extends Weather {
|
||||||
|
|
||||||
|
private static final String WUNDERGROUND_URL = "http://api.wunderground.com/api/";
|
||||||
|
private static final String API_KEY = "";
|
||||||
|
private static final String FEATURES = "/conditions/forecast";
|
||||||
|
private static final String DATA_FORMAT = ".xml";
|
||||||
|
|
||||||
|
private String visibleLocation;
|
||||||
|
|
||||||
|
public WUnderground() {
|
||||||
|
super.baseUrl = WUNDERGROUND_URL;
|
||||||
|
super.encoding = "UTF-8";
|
||||||
|
updateCity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateInfo(int numDays) {
|
||||||
|
visibleLocation = "";
|
||||||
|
String url = buildUrl();
|
||||||
|
super.getData(url);
|
||||||
|
try {
|
||||||
|
parseContent();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.e(getClass().getName(), ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCity() {
|
||||||
|
updateCity();
|
||||||
|
if (visibleLocation.length() > 0) return visibleLocation;
|
||||||
|
return super.getCity();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateCity() {
|
||||||
|
super.location = "Ukraine/Donetsk";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildUrl() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(baseUrl).append(API_KEY).append(FEATURES);
|
||||||
|
sb.append("/lang:").append(Locale.getDefault().getLanguage());
|
||||||
|
sb.append("/q/").append(location);
|
||||||
|
sb.append(DATA_FORMAT);
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseContent() throws XPathExpressionException {
|
||||||
|
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
Node loc = (Node) xpath.evaluate("/response/current_observation/display_location/city", doc, XPathConstants.NODE);
|
||||||
|
visibleLocation = loc.getChildNodes().item(0).getNodeValue();
|
||||||
|
parseCurrentCondition((NodeList) xpath.evaluate("/response/current_observation", doc, XPathConstants.NODESET));
|
||||||
|
parseDayInfo((NodeList) xpath.evaluate("/response/forecast/simpleforecast/forecastdays/forecastday", doc, XPathConstants.NODESET));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseCurrentCondition(NodeList nodeList) {
|
||||||
|
currentCondition = new CurrentCondition();
|
||||||
|
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||||
|
NodeList childNodes = nodeList.item(i).getChildNodes();
|
||||||
|
for (int j = 0; j < childNodes.getLength(); j++) {
|
||||||
|
Node child = childNodes.item(j);
|
||||||
|
// Температура
|
||||||
|
if (child.getNodeName().equals("temp_c")) currentCondition.setTemperature( getData(child) );
|
||||||
|
// Влажность.
|
||||||
|
if (child.getNodeName().equals("relative_humidity")) currentCondition.setHumidity( getData(child) );
|
||||||
|
// Ветер
|
||||||
|
if (child.getNodeName().equals("wind_kph")) currentCondition.getWindInfo().setSpeed( getData(child) + " км/ч " );
|
||||||
|
else if (child.getNodeName().equals("wind_dir")) currentCondition.getWindInfo().setDirection( getData(child) );
|
||||||
|
// Общее
|
||||||
|
if (child.getNodeName().equals("weather")) currentCondition.setSummary( child.getChildNodes().item(0).getNodeValue() );
|
||||||
|
else if (child.getNodeName().equals("icon_url")) currentCondition.setIcon( super.downloadImage( getData(child) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getData(Node child) {
|
||||||
|
return child.getChildNodes().item(0).getNodeValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseDayInfo(NodeList nodeList) throws XPathExpressionException {
|
||||||
|
dayInfo = new ArrayList<DayInfo>();
|
||||||
|
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
|
||||||
|
System.out.println("Count: "+nodeList.getLength());
|
||||||
|
System.out.println(nodeList.item(0).getNodeName());
|
||||||
|
|
||||||
|
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||||
|
Node node = nodeList.item(i);
|
||||||
|
DayInfo info = new DayInfo();
|
||||||
|
|
||||||
|
info.setTemperatureMax( getData( ((Node) xpath.evaluate("/response/forecast/simpleforecast/forecastdays/forecastday/high/celsius", node, XPathConstants.NODE)) ) );
|
||||||
|
info.setTemperature( getData( ((Node) xpath.evaluate("/response/forecast/simpleforecast/forecastdays/forecastday/low/celsius", node, XPathConstants.NODE)) ) );
|
||||||
|
info.setSummary( getData( ((Node) xpath.evaluate("/response/forecast/simpleforecast/forecastdays/forecastday/conditions", node, XPathConstants.NODE)) ) );
|
||||||
|
info.setIcon(super.downloadImage( getData( ((Node) xpath.evaluate("/response/forecast/simpleforecast/forecastdays/forecastday/icon_url", node, XPathConstants.NODE)) ) ));
|
||||||
|
info.getWindInfo().setSpeed( getData( ((Node) xpath.evaluate("/response/forecast/simpleforecast/forecastdays/forecastday/avewind/kph", node, XPathConstants.NODE)) ) + " км/ч " );
|
||||||
|
info.getWindInfo().setDirection( getData( ((Node) xpath.evaluate("/response/forecast/simpleforecast/forecastdays/forecastday/avewind/dir", node, XPathConstants.NODE)) ) );
|
||||||
|
|
||||||
|
dayInfo.add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*private void parseDayInfo(NodeList nodeList) throws XPathExpressionException {
|
||||||
|
dayInfo = new ArrayList<DayInfo>();
|
||||||
|
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
|
||||||
|
System.out.println("Count: "+nodeList.getLength());
|
||||||
|
System.out.println(nodeList.item(0).getNodeName());
|
||||||
|
|
||||||
|
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||||
|
Node node = nodeList.item(i);
|
||||||
|
DayInfo info = new DayInfo();
|
||||||
|
|
||||||
|
Node ololo = ((Node) xpath.evaluate("/high/celsius", node, XPathConstants.NODE));
|
||||||
|
System.out.println("Name: "+ololo.getNodeName());
|
||||||
|
System.out.println("NumChilds: "+ololo.getChildNodes().getLength());
|
||||||
|
System.out.println("Celsius: "+ololo.getChildNodes().item(0).getNodeValue());
|
||||||
|
|
||||||
|
info.setTemperatureMax( getData( ((Node) xpath.evaluate("/high/celsius", node, XPathConstants.NODE)) ) );
|
||||||
|
info.setTemperature( getData( ((Node) xpath.evaluate("/low/celsius", node, XPathConstants.NODE)) ) );
|
||||||
|
info.setSummary( getData( ((Node) xpath.evaluate("/conditions", node, XPathConstants.NODE)) ) );
|
||||||
|
info.setIcon(super.downloadImage( getData( ((Node) xpath.evaluate("/icon_url", node, XPathConstants.NODE)) ) ));
|
||||||
|
info.getWindInfo().setSpeed( getData( ((Node) xpath.evaluate("/avewind/kph", node, XPathConstants.NODE)) ) + " км/ч " );
|
||||||
|
info.getWindInfo().setDirection( getData( ((Node) xpath.evaluate("/avewind/dir", node, XPathConstants.NODE)) ) );
|
||||||
|
|
||||||
|
dayInfo.add(info);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
126
src/com/annimon/screenweather/weather/Weather.java
Normal file
126
src/com/annimon/screenweather/weather/Weather.java
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* aNNiMON 2012
|
||||||
|
* For more info visit http://annimon.com/
|
||||||
|
*/
|
||||||
|
package com.annimon.screenweather.weather;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.util.Log;
|
||||||
|
import com.annimon.screenweather.CurrentCondition;
|
||||||
|
import com.annimon.screenweather.DayInfo;
|
||||||
|
import com.annimon.screenweather.StringEncoder;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public abstract class Weather {
|
||||||
|
|
||||||
|
protected static final String CP1251 = "CP1251";
|
||||||
|
|
||||||
|
/** Адрес базового пути (без параметров) к информеру. */
|
||||||
|
protected String baseUrl;
|
||||||
|
|
||||||
|
/** Кодировка получаемых данных. */
|
||||||
|
protected String encoding;
|
||||||
|
|
||||||
|
/** Информация с сайта, например xml-данные, rss... */
|
||||||
|
protected Document doc;
|
||||||
|
|
||||||
|
|
||||||
|
/** Текущие данные (Current Condition).*/
|
||||||
|
protected CurrentCondition currentCondition;
|
||||||
|
|
||||||
|
/** Данные по дням. */
|
||||||
|
protected ArrayList<DayInfo> dayInfo;
|
||||||
|
|
||||||
|
/** Город, для которого нужно получить информацию. */
|
||||||
|
protected String location;
|
||||||
|
|
||||||
|
public CurrentCondition getCurrentCondition() {
|
||||||
|
return currentCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDaysCount() {
|
||||||
|
return dayInfo.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCity() {
|
||||||
|
updateCity();
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DayInfo getDayInfo(int day) {
|
||||||
|
if ( (0 <= day) && (day < dayInfo.size())) {
|
||||||
|
return dayInfo.get(day);
|
||||||
|
}
|
||||||
|
return new DayInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void updateInfo(int numDays);
|
||||||
|
public abstract void updateCity();
|
||||||
|
|
||||||
|
protected void getData(String urlsite) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
URI uri = URI.create(urlsite);
|
||||||
|
URL url = uri.normalize().toURL();
|
||||||
|
URLConnection conn = url.openConnection();
|
||||||
|
conn.setRequestProperty("Accept-Language", Locale.getDefault().getLanguage());
|
||||||
|
|
||||||
|
boolean useCP1251 = false;
|
||||||
|
Charset charset = Charset.defaultCharset();
|
||||||
|
if (encoding != null) {
|
||||||
|
if (encoding.equals(CP1251)) useCP1251 = true;
|
||||||
|
else charset = Charset.forName(encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (useCP1251) {
|
||||||
|
InputStream reader = conn.getInputStream();
|
||||||
|
int readChar;
|
||||||
|
while ( (readChar = reader.read()) != -1) {
|
||||||
|
sb.append( StringEncoder.decodeCharCP1251(readChar) );
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
} else {
|
||||||
|
InputStreamReader reader = new InputStreamReader(conn.getInputStream(), charset);
|
||||||
|
int readChar;
|
||||||
|
while ( (readChar = reader.read()) != -1) {
|
||||||
|
sb.append( (char) readChar );
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StringReader sr = new StringReader( sb.toString() );
|
||||||
|
InputSource isource = new InputSource(sr);
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
factory.setNamespaceAware(true);
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
doc = builder.parse(isource);
|
||||||
|
doc.getDocumentElement().normalize();
|
||||||
|
sr.close();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.e(getClass().getName(), ex.getMessage(), ex);
|
||||||
|
doc = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Bitmap downloadImage(String url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user