From 2e1faf2fbd074fb89ac7a03d6754fbe338d38642 Mon Sep 17 00:00:00 2001 From: survivingwithandroid Date: Tue, 25 Feb 2014 14:31:32 +0100 Subject: [PATCH] Initial Commit Weather App --- AndroidYahooWeather/.gitignore | 4 + AndroidYahooWeather/build.gradle | 16 + AndroidYahooWeather/gradle.properties | 18 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + AndroidYahooWeather/gradlew | 164 +++ AndroidYahooWeather/gradlew.bat | 90 ++ AndroidYahooWeather/settings.gradle | 1 + AndroidYahooWeather/weather/.gitignore | 1 + AndroidYahooWeather/weather/build.gradle | 24 + .../weather/libs/add_volley_libe_here.txt | 0 .../weather/proguard-rules.txt | 17 + .../weather/src/main/AndroidManifest.xml | 43 + .../vending/billing/IInAppBillingService.aidl | 144 +++ .../weather/src/main/ic_launcher-web.png | Bin 0 -> 47065 bytes .../survivingwithandroid/weather/Config.java | 21 + .../weather/MainActivity.java | 303 ++++++ .../weather/billing/util/Base64.java | 570 ++++++++++ .../billing/util/Base64DecoderException.java | 32 + .../weather/billing/util/IabException.java | 43 + .../weather/billing/util/IabHelper.java | 991 ++++++++++++++++++ .../weather/billing/util/IabResult.java | 45 + .../weather/billing/util/Inventory.java | 91 ++ .../weather/billing/util/Purchase.java | 63 ++ .../weather/billing/util/Security.java | 123 +++ .../weather/billing/util/SkuDetails.java | 58 + .../weather/billing/util/SwABillingUtil.java | 73 ++ .../weather/model/CityResult.java | 60 ++ .../weather/model/Weather.java | 76 ++ .../provider/IWeatherImageProvider.java | 30 + .../provider/WeatherImageProvider.java | 45 + .../weather/provider/YahooClient.java | 239 +++++ .../weather/settings/CityFinderActivity.java | 152 +++ .../settings/WeatherPreferenceActivity.java | 61 ++ .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 7721 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 3769 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 12329 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 24654 bytes .../weather/src/main/res/drawable/eye.png | Bin 0 -> 5115 bytes .../src/main/res/drawable/humidity.png | Bin 0 -> 13892 bytes .../src/main/res/drawable/ic_menu_refresh.png | Bin 0 -> 2025 bytes .../src/main/res/drawable/line_shape_blue.xml | 9 + .../main/res/drawable/line_shape_green.xml | 9 + .../src/main/res/drawable/line_shape_red.xml | 9 + .../weather/src/main/res/drawable/moon.png | Bin 0 -> 1977 bytes .../src/main/res/drawable/pressure.png | Bin 0 -> 6832 bytes .../weather/src/main/res/drawable/sun.png | Bin 0 -> 11254 bytes .../src/main/res/drawable/temperature.png | Bin 0 -> 2551 bytes .../weather/src/main/res/drawable/wind.png | Bin 0 -> 6728 bytes .../main/res/layout-land/fragment_main.xml | 261 +++++ .../src/main/res/layout/activity_main.xml | 25 + .../src/main/res/layout/cityfinder_layout.xml | 43 + .../src/main/res/layout/cityresult_layout.xml | 27 + .../src/main/res/layout/fragment_main.xml | 254 +++++ .../src/main/res/layout/popdonate_layout.xml | 54 + .../src/main/res/layout/progress_bar.xml | 24 + .../weather/src/main/res/menu/main.xml | 48 + .../src/main/res/values-w820dp/dimens.xml | 6 + .../weather/src/main/res/values/colors.xml | 22 + .../weather/src/main/res/values/dimens.xml | 6 + .../weather/src/main/res/values/strings.xml | 40 + .../weather/src/main/res/values/styles.xml | 44 + .../src/main/res/xml/weather_prefs.xml | 38 + 63 files changed, 4523 insertions(+) create mode 100644 AndroidYahooWeather/.gitignore create mode 100644 AndroidYahooWeather/build.gradle create mode 100644 AndroidYahooWeather/gradle.properties create mode 100644 AndroidYahooWeather/gradle/wrapper/gradle-wrapper.jar create mode 100644 AndroidYahooWeather/gradle/wrapper/gradle-wrapper.properties create mode 100644 AndroidYahooWeather/gradlew create mode 100644 AndroidYahooWeather/gradlew.bat create mode 100644 AndroidYahooWeather/settings.gradle create mode 100644 AndroidYahooWeather/weather/.gitignore create mode 100644 AndroidYahooWeather/weather/build.gradle create mode 100644 AndroidYahooWeather/weather/libs/add_volley_libe_here.txt create mode 100644 AndroidYahooWeather/weather/proguard-rules.txt create mode 100644 AndroidYahooWeather/weather/src/main/AndroidManifest.xml create mode 100644 AndroidYahooWeather/weather/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl create mode 100644 AndroidYahooWeather/weather/src/main/ic_launcher-web.png create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/Config.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/MainActivity.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64DecoderException.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabException.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabHelper.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabResult.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Inventory.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Purchase.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Security.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SkuDetails.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SwABillingUtil.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/CityResult.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/Weather.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/IWeatherImageProvider.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/WeatherImageProvider.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/YahooClient.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/CityFinderActivity.java create mode 100644 AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/WeatherPreferenceActivity.java create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/eye.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/humidity.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/ic_menu_refresh.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/line_shape_blue.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/line_shape_green.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/line_shape_red.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/moon.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/pressure.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/sun.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/temperature.png create mode 100644 AndroidYahooWeather/weather/src/main/res/drawable/wind.png create mode 100644 AndroidYahooWeather/weather/src/main/res/layout-land/fragment_main.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/layout/activity_main.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/layout/cityfinder_layout.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/layout/cityresult_layout.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/layout/fragment_main.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/layout/popdonate_layout.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/layout/progress_bar.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/menu/main.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/values-w820dp/dimens.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/values/colors.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/values/dimens.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/values/strings.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/values/styles.xml create mode 100644 AndroidYahooWeather/weather/src/main/res/xml/weather_prefs.xml diff --git a/AndroidYahooWeather/.gitignore b/AndroidYahooWeather/.gitignore new file mode 100644 index 0000000..d6bfc95 --- /dev/null +++ b/AndroidYahooWeather/.gitignore @@ -0,0 +1,4 @@ +.gradle +/local.properties +/.idea/workspace.xml +.DS_Store diff --git a/AndroidYahooWeather/build.gradle b/AndroidYahooWeather/build.gradle new file mode 100644 index 0000000..9597164 --- /dev/null +++ b/AndroidYahooWeather/build.gradle @@ -0,0 +1,16 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.7.+' + } +} + +allprojects { + repositories { + mavenCentral() + } +} diff --git a/AndroidYahooWeather/gradle.properties b/AndroidYahooWeather/gradle.properties new file mode 100644 index 0000000..5d08ba7 --- /dev/null +++ b/AndroidYahooWeather/gradle.properties @@ -0,0 +1,18 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Settings specified in this file will override any Gradle settings +# configured through the IDE. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true \ No newline at end of file diff --git a/AndroidYahooWeather/gradle/wrapper/gradle-wrapper.jar b/AndroidYahooWeather/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..8c0fb64a8698b08ecc4158d828ca593c4928e9dd GIT binary patch literal 49896 zcmagFb986H(k`5d^NVfUwr$(C?M#x1ZQHiZiEVpg+jrjgoQrerx!>1o_ul)D>ebz~ zs=Mmxr&>W81QY-S1PKWQ%N-;H^tS;2*XwVA`dej1RRn1z<;3VgfE4~kaG`A%QSPsR z#ovnZe+tS9%1MfeDyz`RirvdjPRK~p(#^q2(^5@O&NM19EHdvN-A&StN>0g6QA^VN z0Gx%Gq#PD$QMRFzmK+utjS^Y1F0e8&u&^=w5K<;4Rz|i3A=o|IKLY+g`iK6vfr9?+ z-`>gmU&i?FGSL5&F?TXFu`&Js6h;15QFkXp2M1H9|Eq~bpov-GU(uz%mH0n55wUl- zv#~ccAz`F5wlQ>e_KlJS3@{)B?^v*EQM=IxLa&76^y51a((wq|2-`qON>+4dLc{Oo z51}}o^Zen(oAjxDK7b++9_Yg`67p$bPo3~BCpGM7uAWmvIhWc5Gi+gQZ|Pwa-Gll@<1xmcPy z|NZmu6m)g5Ftu~BG&Xdxclw7Cij{xbBMBn-LMII#Slp`AElb&2^Hw+w>(3crLH!;I zN+Vk$D+wP1#^!MDCiad@vM>H#6+`Ct#~6VHL4lzmy;lSdk>`z6)=>Wh15Q2)dQtGqvn0vJU@+(B5{MUc*qs4!T+V=q=wy)<6$~ z!G>e_4dN@lGeF_$q9`Ju6Ncb*x?O7=l{anm7Eahuj_6lA{*#Gv*TaJclevPVbbVYu z(NY?5q+xxbO6%g1xF0r@Ix8fJ~u)VRUp`S%&rN$&e!Od`~s+64J z5*)*WSi*i{k%JjMSIN#X;jC{HG$-^iX+5f5BGOIHWAl*%15Z#!xntpk($-EGKCzKa zT7{siZ9;4TICsWQ$pu&wKZQTCvpI$Xvzwxoi+XkkpeE&&kFb!B?h2hi%^YlXt|-@5 zHJ~%AN!g_^tmn1?HSm^|gCE#!GRtK2(L{9pL#hp0xh zME}|DB>(5)`iE7CM)&_+S}-Bslc#@B5W4_+k4Cp$l>iVyg$KP>CN?SVGZ(&02>iZK zB<^HP$g$Lq*L$BWd?2(F?-MUbNWTJVQdW7$#8a|k_30#vHAD1Z{c#p;bETk0VnU5A zBgLe2HFJ3032$G<`m*OB!KM$*sdM20jm)It5OSru@tXpK5LT>#8)N!*skNu1$TpIw zufjjdp#lyH5bZ%|Iuo|iu9vG1HrIVWLH>278xo>aVBkPN3V$~!=KnlXQ4eDqS7%E% zQ!z^$Q$b^6Q)g#cLpwur(|<0gWHo6A6jc;n`t(V9T;LzTAU{IAu*uEQ%Ort1k+Kn+f_N`9|bxYC+~Z1 zCC1UCWv*Orx$_@ydv9mIe(liLfOr7mhbV@tKw{6)q^1DH1nmvZ0cj215R<~&I<4S| zgnr;9Cdjqpz#o8i0CQjtl`}{c*P)aSdH|abxGdrR)-3z+02-eX(k*B)Uqv6~^nh** z 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/AndroidYahooWeather/gradlew.bat b/AndroidYahooWeather/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/AndroidYahooWeather/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/AndroidYahooWeather/settings.gradle b/AndroidYahooWeather/settings.gradle new file mode 100644 index 0000000..b611c80 --- /dev/null +++ b/AndroidYahooWeather/settings.gradle @@ -0,0 +1 @@ +include ':weather' diff --git a/AndroidYahooWeather/weather/.gitignore b/AndroidYahooWeather/weather/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/AndroidYahooWeather/weather/.gitignore @@ -0,0 +1 @@ +/build diff --git a/AndroidYahooWeather/weather/build.gradle b/AndroidYahooWeather/weather/build.gradle new file mode 100644 index 0000000..433105d --- /dev/null +++ b/AndroidYahooWeather/weather/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'android' + +android { + compileSdkVersion 17 + buildToolsVersion '19.0.0' + + defaultConfig { + minSdkVersion 11 + targetSdkVersion 19 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile 'com.android.support:appcompat-v7:+' + compile files('libs/volley.jar') +} diff --git a/AndroidYahooWeather/weather/libs/add_volley_libe_here.txt b/AndroidYahooWeather/weather/libs/add_volley_libe_here.txt new file mode 100644 index 0000000..e69de29 diff --git a/AndroidYahooWeather/weather/proguard-rules.txt b/AndroidYahooWeather/weather/proguard-rules.txt new file mode 100644 index 0000000..5da226c --- /dev/null +++ b/AndroidYahooWeather/weather/proguard-rules.txt @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in D:/DevMobile/sdk1/eclipse_Android_SDK/android-sdk_r18-windows/android-sdk-windows/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: + +# 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 *; +#} \ No newline at end of file diff --git a/AndroidYahooWeather/weather/src/main/AndroidManifest.xml b/AndroidYahooWeather/weather/src/main/AndroidManifest.xml new file mode 100644 index 0000000..0a7d7c5 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AndroidYahooWeather/weather/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl b/AndroidYahooWeather/weather/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl new file mode 100644 index 0000000..2a492f7 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl @@ -0,0 +1,144 @@ +/* + * 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.android.vending.billing; + +import android.os.Bundle; + +/** + * InAppBillingService is the service that provides in-app billing version 3 and beyond. + * This service provides the following features: + * 1. Provides a new API to get details of in-app items published for the app including + * price, type, title and description. + * 2. The purchase flow is synchronous and purchase information is available immediately + * after it completes. + * 3. Purchase information of in-app purchases is maintained within the Google Play system + * till the purchase is consumed. + * 4. An API to consume a purchase of an inapp item. All purchases of one-time + * in-app items are consumable and thereafter can be purchased again. + * 5. An API to get current purchases of the user immediately. This will not contain any + * consumed purchases. + * + * All calls will give a response code with the following possible values + * RESULT_OK = 0 - success + * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog + * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested + * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase + * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API + * RESULT_ERROR = 6 - Fatal error during the API action + * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned + * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned + */ +interface IInAppBillingService { + /** + * Checks support for the requested billing API version, package and in-app type. + * Minimum API version supported by this interface is 3. + * @param apiVersion the billing version which the app is using + * @param packageName the package name of the calling app + * @param type type of the in-app item being purchased "inapp" for one-time purchases + * and "subs" for subscription. + * @return RESULT_OK(0) on success, corresponding result code on failures + */ + int isBillingSupported(int apiVersion, String packageName, String type); + + /** + * Provides details of a list of SKUs + * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle + * with a list JSON strings containing the productId, price, title and description. + * This API can be called with a maximum of 20 SKUs. + * @param apiVersion billing API version that the Third-party is using + * @param packageName the package name of the calling app + * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST" + * @return Bundle containing the following key-value pairs + * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on + * failure as listed above. + * "DETAILS_LIST" with a StringArrayList containing purchase information + * in JSON format similar to: + * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00", + * "title : "Example Title", "description" : "This is an example description" }' + */ + Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle); + + /** + * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU, + * the type, a unique purchase token and an optional developer payload. + * @param apiVersion billing API version that the app is using + * @param packageName package name of the calling app + * @param sku the SKU of the in-app item as published in the developer console + * @param type the type of the in-app item ("inapp" for one-time purchases + * and "subs" for subscription). + * @param developerPayload optional argument to be sent back with the purchase information + * @return Bundle containing the following key-value pairs + * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on + * failure as listed above. + * "BUY_INTENT" - PendingIntent to start the purchase flow + * + * The Pending intent should be launched with startIntentSenderForResult. When purchase flow + * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. + * If the purchase is successful, the result data will contain the following key-value pairs + * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on + * failure as listed above. + * "INAPP_PURCHASE_DATA" - String in JSON format similar to + * '{"orderId":"12999763169054705758.1371079406387615", + * "packageName":"com.example.app", + * "productId":"exampleSku", + * "purchaseTime":1345678900000, + * "purchaseToken" : "122333444455555", + * "developerPayload":"example developer payload" }' + * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that + * was signed with the private key of the developer + * TODO: change this to app-specific keys. + */ + Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type, + String developerPayload); + + /** + * Returns the current SKUs owned by the user of the type and package name specified along with + * purchase information and a signature of the data to be validated. + * This will return all SKUs that have been purchased in V3 and managed items purchased using + * V1 and V2 that have not been consumed. + * @param apiVersion billing API version that the app is using + * @param packageName package name of the calling app + * @param type the type of the in-app items being requested + * ("inapp" for one-time purchases and "subs" for subscription). + * @param continuationToken to be set as null for the first call, if the number of owned + * skus are too many, a continuationToken is returned in the response bundle. + * This method can be called again with the continuation token to get the next set of + * owned skus. + * @return Bundle containing the following key-value pairs + * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on + * failure as listed above. + * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs + * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information + * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures + * of the purchase information + * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the + * next set of in-app purchases. Only set if the + * user has more owned skus than the current list. + */ + Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken); + + /** + * Consume the last purchase of the given SKU. This will result in this item being removed + * from all subsequent responses to getPurchases() and allow re-purchase of this item. + * @param apiVersion billing API version that the app is using + * @param packageName package name of the calling app + * @param purchaseToken token in the purchase information JSON that identifies the purchase + * to be consumed + * @return 0 if consumption succeeded. Appropriate error values for failures. + */ + int consumePurchase(int apiVersion, String packageName, String purchaseToken); +} diff --git a/AndroidYahooWeather/weather/src/main/ic_launcher-web.png b/AndroidYahooWeather/weather/src/main/ic_launcher-web.png new file mode 100644 index 0000000000000000000000000000000000000000..4b14629c415332bd53a76a230dccf2d32a9829c4 GIT binary patch literal 47065 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 literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/Config.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/Config.java new file mode 100644 index 0000000..519e12f --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/Config.java @@ -0,0 +1,21 @@ +package com.survivingwithandroid.weather; + +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public class Config { + + public static int MAX_CITY_RESULT = 10; +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/MainActivity.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/MainActivity.java new file mode 100644 index 0000000..852addd --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/MainActivity.java @@ -0,0 +1,303 @@ +package com.survivingwithandroid.weather; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.preference.PreferenceManager; + +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.volley.RequestQueue; +import com.android.volley.toolbox.Volley; +import com.survivingwithandroid.weather.billing.util.IabHelper; +import com.survivingwithandroid.weather.billing.util.IabResult; +import com.survivingwithandroid.weather.billing.util.SwABillingUtil; +import com.survivingwithandroid.weather.model.Weather; +import com.survivingwithandroid.weather.provider.IWeatherImageProvider; +import com.survivingwithandroid.weather.provider.WeatherImageProvider; +import com.survivingwithandroid.weather.provider.YahooClient; +import com.survivingwithandroid.weather.settings.WeatherPreferenceActivity; + +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public class MainActivity extends Activity { + + private RequestQueue requestQueue; + private SharedPreferences prefs; + private MenuItem refreshItem; + TextView tvDescrWeather; + TextView tvLocation; + TextView tvTemperature; + TextView tvTempUnit; + TextView tvTempMin; + TextView tvTempMax; + TextView tvHum; + TextView tvWindSpeed; + TextView tvWindDeg; + TextView tvPress; + TextView tvPressStatus; + TextView tvVisibility; + ImageView weatherImage; + TextView tvSunrise; + TextView tvSunset; + + private IabHelper mHelper ; + + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.d("SwA", "onCreate"); + super.onCreate(savedInstanceState); + setContentView(R.layout.fragment_main); + requestQueue = Volley.newRequestQueue(getApplicationContext()); + prefs = PreferenceManager.getDefaultSharedPreferences(this); + + tvDescrWeather = (TextView) findViewById(R.id.descrWeather); + tvLocation = (TextView) findViewById(R.id.location); + tvTemperature = (TextView) findViewById(R.id.temp); + tvTempUnit = (TextView) findViewById(R.id.tempUnit); + tvTempMin = (TextView) findViewById(R.id.tempMin); + tvTempMax = (TextView) findViewById(R.id.tempMax); + tvHum = (TextView) findViewById(R.id.humidity); + tvWindSpeed = (TextView) findViewById(R.id.windSpeed); + tvWindDeg = (TextView) findViewById(R.id.windDeg); + tvPress = (TextView) findViewById(R.id.pressure); + tvPressStatus = (TextView) findViewById(R.id.pressureStat); + tvVisibility = (TextView) findViewById(R.id.visibility); + weatherImage = (ImageView) findViewById(R.id.imgWeather); + tvSunrise = (TextView) findViewById(R.id.sunrise); + tvSunset = (TextView) findViewById(R.id.sunset); + + String base64EncodedPublicKey= SwABillingUtil.KEY; + mHelper = new IabHelper(this, base64EncodedPublicKey); + mHelper.enableDebugLogging(true); + mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { + public void onIabSetupFinished(IabResult result) { + //Log.d("SwA", "Setup finished."); + + if (!result.isSuccess()) { + // Oh noes, there was a problem. + + Toast.makeText(MainActivity.this, "Billing error ["+result.getMessage()+"]", Toast.LENGTH_LONG).show(); + return; + } + + // Have we been disposed of in the meantime? If so, quit. + if (mHelper == null) return; + + // IAB is fully set up. Now, let's get an inventory of stuff we own. + // Log.d("SwA", "Setup successful."); + } + }); + + refreshData(); + + } + + + + private void refreshData() { + + if (prefs == null) + return ; + + + String woeid = prefs.getString("woeid", null); + //Log.d("SwA", "WOEID ["+woeid+"]"); + if (woeid != null) { + String loc = prefs.getString("cityName", null) + "," + prefs.getString("country", null); + String unit = prefs.getString("swa_temp_unit", null); + handleProgressBar(true); + + YahooClient.getWeather(woeid, unit, requestQueue, new YahooClient.WeatherClientListener() { + @Override + public void onWeatherResponse(Weather weather) { + //Log.d("SwA", "Weather ["+weather+"] - Cond ["+weather.condition+"] - Temp ["+weather.condition.temp+"]"); + int code = weather.condition.code; + + tvDescrWeather.setText(weather.condition.description); + tvLocation.setText(weather.location.name + "," + weather.location.region + "," + weather.location.country); + // Temperature data + tvTemperature.setText("" + weather.condition.temp); + + int resId = getResource(weather.units.temperature, weather.condition.temp); + ( (TextView) findViewById(R.id.lineTxt)).setBackgroundResource(resId); + + tvTempUnit.setText(weather.units.temperature); + tvTempMin.setText("" + weather.forecast.tempMin + " " + weather.units.temperature); + tvTempMax.setText("" + weather.forecast.tempMax + " " + weather.units.temperature); + + // Humidity data + tvHum.setText("" + weather.atmosphere.humidity + " %"); + + // Wind data + tvWindSpeed.setText("" + weather.wind.speed + " " + weather.units.speed); + tvWindDeg.setText("" + weather.wind.direction + "°"); + + // Pressure data + tvPress.setText("" + weather.atmosphere.pressure + " " + weather.units.pressure); + int status = weather.atmosphere.rising; + String iconStat = ""; + switch (status) { + case 0 : + iconStat = "-"; + break; + case 1 : + iconStat = "+"; + break; + case 2 : + iconStat = "-"; + break; + }; + tvPressStatus.setText(iconStat); + + // Visibility + tvVisibility.setText("" + weather.atmosphere.visibility + " " + weather.units.distance); + + // Astronomy + tvSunrise.setText(weather.astronomy.sunRise); + tvSunset.setText(weather.astronomy.sunSet); + + // Update + + IWeatherImageProvider provider = new WeatherImageProvider(); + provider.getImage(code, requestQueue, new IWeatherImageProvider.WeatherImageListener() { + @Override + public void onImageReady(Bitmap image) { + weatherImage.setImageBitmap(image); + } + }); + handleProgressBar(false); + } + }); + + + } + } + + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + //Log.d("SwA", "onActivityResult(" + requestCode + "," + resultCode + "," + data); + if (mHelper == null) return; + + // Pass on the activity result to the helper for handling + if (!mHelper.handleActivityResult(requestCode, resultCode, data)) { + // not handled, so handle it ourselves (here's where you'd + // perform any handling of activity results not related to in-app + // billing... + super.onActivityResult(requestCode, resultCode, data); + } + else { + // Log.d("SwA", "onActivityResult handled by IABUtil."); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { + Intent i = new Intent(); + i.setClass(this, WeatherPreferenceActivity.class); + startActivity(i); + } + else if (id == R.id.action_refresh) { + refreshItem = item; + refreshData(); + } + else if (id == R.id.action_share) { + String playStoreLink = "https://play.google.com/store/apps/details?id=" + + getPackageName(); + + String msg = getResources().getString(R.string.share_msg) + playStoreLink; + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, msg); + sendIntent.setType("text/plain"); + startActivity(sendIntent); + } + else if (id == R.id.action_donate) { + SwABillingUtil.showDonateDialog(this, mHelper, this); + } + return super.onOptionsItemSelected(item); + } + + + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mHelper != null) mHelper.dispose(); + mHelper = null; + } + + + + private void handleProgressBar(boolean visible) { + if (refreshItem == null) + return ; + + if (visible) + refreshItem.setActionView(R.layout.progress_bar); + else + refreshItem.setActionView(null); + } + + + private float convertToC(String unit, float val) { + if (unit.equalsIgnoreCase("°C")) + return val; + + return (float) ((val - 32) / 1.8); + } + + private int getResource(String unit, float val) { + float temp = convertToC(unit, val); + Log.d("SwA", "Temp ["+temp+"]"); + int resId = 0; + if (temp < 10) + resId = R.drawable.line_shape_blue; + else if (temp >= 10 && temp <=24) + resId = R.drawable.line_shape_green; + else if (temp > 25) + resId = R.drawable.line_shape_red; + + return resId; + + } + + + + +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64.java new file mode 100644 index 0000000..1db3548 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64.java @@ -0,0 +1,570 @@ +// Portions copyright 2002, Google, Inc. +// +// 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.survivingwithandroid.weather.billing.util; + +// This code was converted from code at http://iharder.sourceforge.net/base64/ +// Lots of extraneous features were removed. +/* The original code said: + *

+ * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit + * http://iharder.net/xmlizable + * periodically to check for updates or to contribute improvements. + *

+ * + * @author Robert Harder + * @author rharder@usa.net + * @version 1.3 + */ + +/** + * Base64 converter class. This code is not a complete MIME encoder; + * it simply converts binary data to base64 data and back. + * + *

Note {@link CharBase64} is a GWT-compatible implementation of this + * class. + */ +public class Base64 { + /** Specify encoding (value is {@code true}). */ + public final static boolean ENCODE = true; + + /** Specify decoding (value is {@code false}). */ + public final static boolean DECODE = false; + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte) '='; + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte) '\n'; + + /** + * The 64 valid Base64 values. + */ + private final static byte[] ALPHABET = + {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', + (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', + (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', + (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', + (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', + (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', + (byte) '9', (byte) '+', (byte) '/'}; + + /** + * The 64 valid web safe Base64 values. + */ + private final static byte[] WEBSAFE_ALPHABET = + {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', + (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', + (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', + (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', + (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', + (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', + (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', + (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', + (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', + (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', + (byte) '9', (byte) '-', (byte) '_'}; + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9, -9 // Decimal 123 - 127 + /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + /** The web safe decodabet */ + private final static byte[] WEBSAFE_DECODABET = + {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 + 62, // Dash '-' sign at decimal 45 + -9, -9, // Decimal 46-47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, // Decimal 91-94 + 63, // Underscore '_' at decimal 95 + -9, // Decimal 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9, -9 // Decimal 123 - 127 + /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + // Indicates white space in encoding + private final static byte WHITE_SPACE_ENC = -5; + // Indicates equals sign in encoding + private final static byte EQUALS_SIGN_ENC = -1; + + /** Defeats instantiation. */ + private Base64() { + } + + /* ******** E N C O D I N G M E T H O D S ******** */ + + /** + * Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accommodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param alphabet is the encoding alphabet + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4(byte[] source, int srcOffset, + int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index alphabet + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = + (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) + | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) + | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); + + switch (numSigBytes) { + case 3: + destination[destOffset] = alphabet[(inBuff >>> 18)]; + destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = alphabet[(inBuff) & 0x3f]; + return destination; + case 2: + destination[destOffset] = alphabet[(inBuff >>> 18)]; + destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + case 1: + destination[destOffset] = alphabet[(inBuff >>> 18)]; + destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = EQUALS_SIGN; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + default: + return destination; + } // end switch + } // end encode3to4 + + /** + * Encodes a byte array into Base64 notation. + * Equivalent to calling + * {@code encodeBytes(source, 0, source.length)} + * + * @param source The data to convert + * @since 1.4 + */ + public static String encode(byte[] source) { + return encode(source, 0, source.length, ALPHABET, true); + } + + /** + * Encodes a byte array into web safe Base64 notation. + * + * @param source The data to convert + * @param doPadding is {@code true} to pad result with '=' chars + * if it does not fall on 3 byte boundaries + */ + public static String encodeWebSafe(byte[] source, boolean doPadding) { + return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding); + } + + /** + * Encodes a byte array into Base64 notation. + * + * @param source the data to convert + * @param off offset in array where conversion should begin + * @param len length of data to convert + * @param alphabet the encoding alphabet + * @param doPadding is {@code true} to pad result with '=' chars + * if it does not fall on 3 byte boundaries + * @since 1.4 + */ + public static String encode(byte[] source, int off, int len, byte[] alphabet, + boolean doPadding) { + byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE); + int outLen = outBuff.length; + + // If doPadding is false, set length to truncate '=' + // padding characters + while (doPadding == false && outLen > 0) { + if (outBuff[outLen - 1] != '=') { + break; + } + outLen -= 1; + } + + return new String(outBuff, 0, outLen); + } + + /** + * Encodes a byte array into Base64 notation. + * + * @param source the data to convert + * @param off offset in array where conversion should begin + * @param len length of data to convert + * @param alphabet is the encoding alphabet + * @param maxLineLength maximum length of one line. + * @return the BASE64-encoded byte array + */ + public static byte[] encode(byte[] source, int off, int len, byte[] alphabet, + int maxLineLength) { + int lenDiv3 = (len + 2) / 3; // ceil(len / 3) + int len43 = lenDiv3 * 4; + byte[] outBuff = new byte[len43 // Main 4:3 + + (len43 / maxLineLength)]; // New lines + + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for (; d < len2; d += 3, e += 4) { + + // The following block of code is the same as + // encode3to4( source, d + off, 3, outBuff, e, alphabet ); + // but inlined for faster encoding (~20% improvement) + int inBuff = + ((source[d + off] << 24) >>> 8) + | ((source[d + 1 + off] << 24) >>> 16) + | ((source[d + 2 + off] << 24) >>> 24); + outBuff[e] = alphabet[(inBuff >>> 18)]; + outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f]; + outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f]; + outBuff[e + 3] = alphabet[(inBuff) & 0x3f]; + + lineLength += 4; + if (lineLength == maxLineLength) { + outBuff[e + 4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // end for: each piece of array + + if (d < len) { + encode3to4(source, d + off, len - d, outBuff, e, alphabet); + + lineLength += 4; + if (lineLength == maxLineLength) { + // Add a last newline + outBuff[e + 4] = NEW_LINE; + e++; + } + e += 4; + } + + assert (e == outBuff.length); + return outBuff; + } + + + /* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes four bytes from array source + * and writes the resulting bytes (up to three of them) + * to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accommodate srcOffset + 4 for + * the source array or destOffset + 3 for + * the destination array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param decodabet the decodabet for decoding Base64 content + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3(byte[] source, int srcOffset, + byte[] destination, int destOffset, byte[] decodabet) { + // Example: Dk== + if (source[srcOffset + 2] == EQUALS_SIGN) { + int outBuff = + ((decodabet[source[srcOffset]] << 24) >>> 6) + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); + + destination[destOffset] = (byte) (outBuff >>> 16); + return 1; + } else if (source[srcOffset + 3] == EQUALS_SIGN) { + // Example: DkL= + int outBuff = + ((decodabet[source[srcOffset]] << 24) >>> 6) + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) + | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); + + destination[destOffset] = (byte) (outBuff >>> 16); + destination[destOffset + 1] = (byte) (outBuff >>> 8); + return 2; + } else { + // Example: DkLE + int outBuff = + ((decodabet[source[srcOffset]] << 24) >>> 6) + | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) + | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) + | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); + + destination[destOffset] = (byte) (outBuff >> 16); + destination[destOffset + 1] = (byte) (outBuff >> 8); + destination[destOffset + 2] = (byte) (outBuff); + return 3; + } + } // end decodeToBytes + + + /** + * Decodes data from Base64 notation. + * + * @param s the string to decode (decoded in default encoding) + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode(String s) throws Base64DecoderException { + byte[] bytes = s.getBytes(); + return decode(bytes, 0, bytes.length); + } + + /** + * Decodes data from web safe Base64 notation. + * Web safe encoding uses '-' instead of '+', '_' instead of '/' + * + * @param s the string to decode (decoded in default encoding) + * @return the decoded data + */ + public static byte[] decodeWebSafe(String s) throws Base64DecoderException { + byte[] bytes = s.getBytes(); + return decodeWebSafe(bytes, 0, bytes.length); + } + + /** + * Decodes Base64 content in byte array format and returns + * the decoded byte array. + * + * @param source The Base64 encoded data + * @return decoded data + * @since 1.3 + * @throws Base64DecoderException + */ + public static byte[] decode(byte[] source) throws Base64DecoderException { + return decode(source, 0, source.length); + } + + /** + * Decodes web safe Base64 content in byte array format and returns + * the decoded data. + * Web safe encoding uses '-' instead of '+', '_' instead of '/' + * + * @param source the string to decode (decoded in default encoding) + * @return the decoded data + */ + public static byte[] decodeWebSafe(byte[] source) + throws Base64DecoderException { + return decodeWebSafe(source, 0, source.length); + } + + /** + * Decodes Base64 content in byte array format and returns + * the decoded byte array. + * + * @param source the Base64 encoded data + * @param off the offset of where to begin decoding + * @param len the length of characters to decode + * @return decoded data + * @since 1.3 + * @throws Base64DecoderException + */ + public static byte[] decode(byte[] source, int off, int len) + throws Base64DecoderException { + return decode(source, off, len, DECODABET); + } + + /** + * Decodes web safe Base64 content in byte array format and returns + * the decoded byte array. + * Web safe encoding uses '-' instead of '+', '_' instead of '/' + * + * @param source the Base64 encoded data + * @param off the offset of where to begin decoding + * @param len the length of characters to decode + * @return decoded data + */ + public static byte[] decodeWebSafe(byte[] source, int off, int len) + throws Base64DecoderException { + return decode(source, off, len, WEBSAFE_DECODABET); + } + + /** + * Decodes Base64 content using the supplied decodabet and returns + * the decoded byte array. + * + * @param source the Base64 encoded data + * @param off the offset of where to begin decoding + * @param len the length of characters to decode + * @param decodabet the decodabet for decoding Base64 content + * @return decoded data + */ + public static byte[] decode(byte[] source, int off, int len, byte[] decodabet) + throws Base64DecoderException { + int len34 = len * 3 / 4; + byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + for (i = 0; i < len; i++) { + sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven bits + sbiDecode = decodabet[sbiCrop]; + + if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or better + if (sbiDecode >= EQUALS_SIGN_ENC) { + // An equals sign (for padding) must not occur at position 0 or 1 + // and must be the last byte[s] in the encoded value + if (sbiCrop == EQUALS_SIGN) { + int bytesLeft = len - i; + byte lastByte = (byte) (source[len - 1 + off] & 0x7f); + if (b4Posn == 0 || b4Posn == 1) { + throw new Base64DecoderException( + "invalid padding byte '=' at byte offset " + i); + } else if ((b4Posn == 3 && bytesLeft > 2) + || (b4Posn == 4 && bytesLeft > 1)) { + throw new Base64DecoderException( + "padding byte '=' falsely signals end of encoded value " + + "at offset " + i); + } else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) { + throw new Base64DecoderException( + "encoded value has invalid trailing byte"); + } + break; + } + + b4[b4Posn++] = sbiCrop; + if (b4Posn == 4) { + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); + b4Posn = 0; + } + } + } else { + throw new Base64DecoderException("Bad Base64 input character at " + i + + ": " + source[i + off] + "(decimal)"); + } + } + + // Because web safe encoding allows non padding base64 encodes, we + // need to pad the rest of the b4 buffer with equal signs when + // b4Posn != 0. There can be at most 2 equal signs at the end of + // four characters, so the b4 buffer must have two or three + // characters. This also catches the case where the input is + // padded with EQUALS_SIGN + if (b4Posn != 0) { + if (b4Posn == 1) { + throw new Base64DecoderException("single trailing character at offset " + + (len - 1)); + } + b4[b4Posn++] = EQUALS_SIGN; + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); + } + + byte[] out = new byte[outBuffPosn]; + System.arraycopy(outBuff, 0, out, 0, outBuffPosn); + return out; + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64DecoderException.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64DecoderException.java new file mode 100644 index 0000000..d3c0f18 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Base64DecoderException.java @@ -0,0 +1,32 @@ +// Copyright 2002, Google, Inc. +// +// 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.survivingwithandroid.weather.billing.util; + +/** + * Exception thrown when encountering an invalid Base64 input character. + * + * @author nelson + */ +public class Base64DecoderException extends Exception { + public Base64DecoderException() { + super(); + } + + public Base64DecoderException(String s) { + super(s); + } + + private static final long serialVersionUID = 1L; +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabException.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabException.java new file mode 100644 index 0000000..56407d9 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabException.java @@ -0,0 +1,43 @@ +/* Copyright (c) 2012 Google Inc. + * + * 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.survivingwithandroid.weather.billing.util; + +/** + * Exception thrown when something went wrong with in-app billing. + * An IabException has an associated IabResult (an error). + * To get the IAB result that caused this exception to be thrown, + * call {@link #getResult()}. + */ +public class IabException extends Exception { + IabResult mResult; + + public IabException(IabResult r) { + this(r, null); + } + public IabException(int response, String message) { + this(new IabResult(response, message)); + } + public IabException(IabResult r, Exception cause) { + super(r.getMessage(), cause); + mResult = r; + } + public IabException(int response, String message, Exception cause) { + this(new IabResult(response, message), cause); + } + + /** Returns the IAB result (error) that this exception signals. */ + public IabResult getResult() { return mResult; } +} \ No newline at end of file diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabHelper.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabHelper.java new file mode 100644 index 0000000..ac4f9b9 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabHelper.java @@ -0,0 +1,991 @@ +/* Copyright (c) 2012 Google Inc. + * + * 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.survivingwithandroid.weather.billing.util; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentSender.SendIntentException; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; + +import com.android.vending.billing.IInAppBillingService; + +import org.json.JSONException; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Provides convenience methods for in-app billing. You can create one instance of this + * class for your application and use it to process in-app billing operations. + * It provides synchronous (blocking) and asynchronous (non-blocking) methods for + * many common in-app billing operations, as well as automatic signature + * verification. + * + * After instantiating, you must perform setup in order to start using the object. + * To perform setup, call the {@link #startSetup} method and provide a listener; + * that listener will be notified when setup is complete, after which (and not before) + * you may call other methods. + * + * After setup is complete, you will typically want to request an inventory of owned + * items and subscriptions. See {@link #queryInventory}, {@link #queryInventoryAsync} + * and related methods. + * + * When you are done with this object, don't forget to call {@link #dispose} + * to ensure proper cleanup. This object holds a binding to the in-app billing + * service, which will leak unless you dispose of it correctly. If you created + * the object on an Activity's onCreate method, then the recommended + * place to dispose of it is the Activity's onDestroy method. + * + * A note about threading: When using this object from a background thread, you may + * call the blocking versions of methods; when using from a UI thread, call + * only the asynchronous versions and handle the results via callbacks. + * Also, notice that you can only call one asynchronous operation at a time; + * attempting to start a second asynchronous operation while the first one + * has not yet completed will result in an exception being thrown. + * + * @author Bruno Oliveira (Google) + * + */ +public class IabHelper { + // Is debug logging enabled? + boolean mDebugLog = false; + String mDebugTag = "IabHelper"; + + // Is setup done? + boolean mSetupDone = false; + + // Has this object been disposed of? (If so, we should ignore callbacks, etc) + boolean mDisposed = false; + + // Are subscriptions supported? + boolean mSubscriptionsSupported = false; + + // Is an asynchronous operation in progress? + // (only one at a time can be in progress) + boolean mAsyncInProgress = false; + + // (for logging/debugging) + // if mAsyncInProgress == true, what asynchronous operation is in progress? + String mAsyncOperation = ""; + + // Context we were passed during initialization + Context mContext; + + // Connection to the service + IInAppBillingService mService; + ServiceConnection mServiceConn; + + // The request code used to launch purchase flow + int mRequestCode; + + // The item type of the current purchase flow + String mPurchasingItemType; + + // Public key for verifying signature, in base64 encoding + String mSignatureBase64 = null; + + // Billing response codes + public static final int BILLING_RESPONSE_RESULT_OK = 0; + public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1; + public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3; + public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4; + public static final int BILLING_RESPONSE_RESULT_DEVELOPER_ERROR = 5; + public static final int BILLING_RESPONSE_RESULT_ERROR = 6; + public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7; + public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8; + + // IAB Helper error codes + public static final int IABHELPER_ERROR_BASE = -1000; + public static final int IABHELPER_REMOTE_EXCEPTION = -1001; + public static final int IABHELPER_BAD_RESPONSE = -1002; + public static final int IABHELPER_VERIFICATION_FAILED = -1003; + public static final int IABHELPER_SEND_INTENT_FAILED = -1004; + public static final int IABHELPER_USER_CANCELLED = -1005; + public static final int IABHELPER_UNKNOWN_PURCHASE_RESPONSE = -1006; + public static final int IABHELPER_MISSING_TOKEN = -1007; + public static final int IABHELPER_UNKNOWN_ERROR = -1008; + public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009; + public static final int IABHELPER_INVALID_CONSUMPTION = -1010; + + // Keys for the responses from InAppBillingService + public static final String RESPONSE_CODE = "RESPONSE_CODE"; + public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST"; + public static final String RESPONSE_BUY_INTENT = "BUY_INTENT"; + public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA"; + public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE"; + public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST"; + public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST"; + public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST"; + public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN"; + + // Item types + public static final String ITEM_TYPE_INAPP = "inapp"; + public static final String ITEM_TYPE_SUBS = "subs"; + + // some fields on the getSkuDetails response bundle + public static final String GET_SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST"; + public static final String GET_SKU_DETAILS_ITEM_TYPE_LIST = "ITEM_TYPE_LIST"; + + /** + * Creates an instance. After creation, it will not yet be ready to use. You must perform + * setup by calling {@link #startSetup} and wait for setup to complete. This constructor does not + * block and is safe to call from a UI thread. + * + * @param ctx Your application or Activity context. Needed to bind to the in-app billing service. + * @param base64PublicKey Your application's public key, encoded in base64. + * This is used for verification of purchase signatures. You can find your app's base64-encoded + * public key in your application's page on Google Play Developer Console. Note that this + * is NOT your "developer public key". + */ + public IabHelper(Context ctx, String base64PublicKey) { + mContext = ctx.getApplicationContext(); + mSignatureBase64 = base64PublicKey; + logDebug("IAB helper created."); + } + + /** + * Enables or disable debug logging through LogCat. + */ + public void enableDebugLogging(boolean enable, String tag) { + checkNotDisposed(); + mDebugLog = enable; + mDebugTag = tag; + } + + public void enableDebugLogging(boolean enable) { + checkNotDisposed(); + mDebugLog = enable; + } + + /** + * Callback for setup process. This listener's {@link #onIabSetupFinished} method is called + * when the setup process is complete. + */ + public interface OnIabSetupFinishedListener { + /** + * Called to notify that setup is complete. + * + * @param result The result of the setup process. + */ + public void onIabSetupFinished(IabResult result); + } + + /** + * Starts the setup process. This will start up the setup process asynchronously. + * You will be notified through the listener when the setup process is complete. + * This method is safe to call from a UI thread. + * + * @param listener The listener to notify when the setup process is complete. + */ + public void startSetup(final OnIabSetupFinishedListener listener) { + // If already set up, can't do it again. + checkNotDisposed(); + if (mSetupDone) throw new IllegalStateException("IAB helper is already set up."); + + // Connection to IAB service + logDebug("Starting in-app billing setup."); + mServiceConn = new ServiceConnection() { + @Override + public void onServiceDisconnected(ComponentName name) { + logDebug("Billing service disconnected."); + mService = null; + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (mDisposed) return; + logDebug("Billing service connected."); + mService = IInAppBillingService.Stub.asInterface(service); + String packageName = mContext.getPackageName(); + try { + logDebug("Checking for in-app billing 3 support."); + + // check for in-app billing v3 support + int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP); + if (response != BILLING_RESPONSE_RESULT_OK) { + if (listener != null) listener.onIabSetupFinished(new IabResult(response, + "Error checking for billing v3 support.")); + + // if in-app purchases aren't supported, neither are subscriptions. + mSubscriptionsSupported = false; + return; + } + logDebug("In-app billing version 3 supported for " + packageName); + + // check for v3 subscriptions support + response = mService.isBillingSupported(3, packageName, ITEM_TYPE_SUBS); + if (response == BILLING_RESPONSE_RESULT_OK) { + logDebug("Subscriptions AVAILABLE."); + mSubscriptionsSupported = true; + } + else { + logDebug("Subscriptions NOT AVAILABLE. Response: " + response); + } + + mSetupDone = true; + } + catch (RemoteException e) { + if (listener != null) { + listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION, + "RemoteException while setting up in-app billing.")); + } + e.printStackTrace(); + return; + } + + if (listener != null) { + listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful.")); + } + } + }; + + Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); + serviceIntent.setPackage("com.android.vending"); + if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) { + // service available to handle that Intent + mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE); + } + else { + // no service available to handle that Intent + if (listener != null) { + listener.onIabSetupFinished( + new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, + "Billing service unavailable on device.")); + } + } + } + + /** + * Dispose of object, releasing resources. It's very important to call this + * method when you are done with this object. It will release any resources + * used by it such as service connections. Naturally, once the object is + * disposed of, it can't be used again. + */ + public void dispose() { + logDebug("Disposing."); + mSetupDone = false; + if (mServiceConn != null) { + logDebug("Unbinding from service."); + if (mContext != null) mContext.unbindService(mServiceConn); + } + mDisposed = true; + mContext = null; + mServiceConn = null; + mService = null; + mPurchaseListener = null; + } + + private void checkNotDisposed() { + if (mDisposed) throw new IllegalStateException("IabHelper was disposed of, so it cannot be used."); + } + + /** Returns whether subscriptions are supported. */ + public boolean subscriptionsSupported() { + checkNotDisposed(); + return mSubscriptionsSupported; + } + + + /** + * Callback that notifies when a purchase is finished. + */ + public interface OnIabPurchaseFinishedListener { + /** + * Called to notify that an in-app purchase finished. If the purchase was successful, + * then the sku parameter specifies which item was purchased. If the purchase failed, + * the sku and extraData parameters may or may not be null, depending on how far the purchase + * process went. + * + * @param result The result of the purchase. + * @param info The purchase information (null if purchase failed) + */ + public void onIabPurchaseFinished(IabResult result, Purchase info); + } + + // The listener registered on launchPurchaseFlow, which we have to call back when + // the purchase finishes + OnIabPurchaseFinishedListener mPurchaseListener; + + public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) { + launchPurchaseFlow(act, sku, requestCode, listener, ""); + } + + public void launchPurchaseFlow(Activity act, String sku, int requestCode, + OnIabPurchaseFinishedListener listener, String extraData) { + launchPurchaseFlow(act, sku, ITEM_TYPE_INAPP, requestCode, listener, extraData); + } + + public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, + OnIabPurchaseFinishedListener listener) { + launchSubscriptionPurchaseFlow(act, sku, requestCode, listener, ""); + } + + public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, + OnIabPurchaseFinishedListener listener, String extraData) { + launchPurchaseFlow(act, sku, ITEM_TYPE_SUBS, requestCode, listener, extraData); + } + + /** + * Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase, + * which will involve bringing up the Google Play screen. The calling activity will be paused while + * the user interacts with Google Play, and the result will be delivered via the activity's + * {@link android.app.Activity#onActivityResult} method, at which point you must call + * this object's {@link #handleActivityResult} method to continue the purchase flow. This method + * MUST be called from the UI thread of the Activity. + * + * @param act The calling activity. + * @param sku The sku of the item to purchase. + * @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or ITEM_TYPE_SUBS) + * @param requestCode A request code (to differentiate from other responses -- + * as in {@link android.app.Activity#startActivityForResult}). + * @param listener The listener to notify when the purchase process finishes + * @param extraData Extra data (developer payload), which will be returned with the purchase data + * when the purchase completes. This extra data will be permanently bound to that purchase + * and will always be returned when the purchase is queried. + */ + public void launchPurchaseFlow(Activity act, String sku, String itemType, int requestCode, + OnIabPurchaseFinishedListener listener, String extraData) { + checkNotDisposed(); + checkSetupDone("launchPurchaseFlow"); + flagStartAsync("launchPurchaseFlow"); + IabResult result; + + if (itemType.equals(ITEM_TYPE_SUBS) && !mSubscriptionsSupported) { + IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, + "Subscriptions are not available."); + flagEndAsync(); + if (listener != null) listener.onIabPurchaseFinished(r, null); + return; + } + + try { + logDebug("Constructing buy intent for " + sku + ", item type: " + itemType); + Bundle buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType, extraData); + int response = getResponseCodeFromBundle(buyIntentBundle); + if (response != BILLING_RESPONSE_RESULT_OK) { + logError("Unable to buy item, Error response: " + getResponseDesc(response)); + flagEndAsync(); + result = new IabResult(response, "Unable to buy item"); + if (listener != null) listener.onIabPurchaseFinished(result, null); + return; + } + + PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT); + logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode); + mRequestCode = requestCode; + mPurchaseListener = listener; + mPurchasingItemType = itemType; + act.startIntentSenderForResult(pendingIntent.getIntentSender(), + requestCode, new Intent(), + Integer.valueOf(0), Integer.valueOf(0), + Integer.valueOf(0)); + } + catch (SendIntentException e) { + logError("SendIntentException while launching purchase flow for sku " + sku); + e.printStackTrace(); + flagEndAsync(); + + result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent."); + if (listener != null) listener.onIabPurchaseFinished(result, null); + } + catch (RemoteException e) { + logError("RemoteException while launching purchase flow for sku " + sku); + e.printStackTrace(); + flagEndAsync(); + + result = new IabResult(IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow"); + if (listener != null) listener.onIabPurchaseFinished(result, null); + } + } + + /** + * Handles an activity result that's part of the purchase flow in in-app billing. If you + * are calling {@link #launchPurchaseFlow}, then you must call this method from your + * Activity's {@link android.app.Activity@onActivityResult} method. This method + * MUST be called from the UI thread of the Activity. + * + * @param requestCode The requestCode as you received it. + * @param resultCode The resultCode as you received it. + * @param data The data (Intent) as you received it. + * @return Returns true if the result was related to a purchase flow and was handled; + * false if the result was not related to a purchase, in which case you should + * handle it normally. + */ + public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { + IabResult result; + if (requestCode != mRequestCode) return false; + + checkNotDisposed(); + checkSetupDone("handleActivityResult"); + + // end of async purchase operation that started on launchPurchaseFlow + flagEndAsync(); + + if (data == null) { + logError("Null data in IAB activity result."); + result = new IabResult(IABHELPER_BAD_RESPONSE, "Null data in IAB result"); + if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); + return true; + } + + int responseCode = getResponseCodeFromIntent(data); + String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); + String dataSignature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE); + + if (resultCode == Activity.RESULT_OK && responseCode == BILLING_RESPONSE_RESULT_OK) { + logDebug("Successful resultcode from purchase activity."); + logDebug("Purchase data: " + purchaseData); + logDebug("Data signature: " + dataSignature); + logDebug("Extras: " + data.getExtras()); + logDebug("Expected item type: " + mPurchasingItemType); + + if (purchaseData == null || dataSignature == null) { + logError("BUG: either purchaseData or dataSignature is null."); + logDebug("Extras: " + data.getExtras().toString()); + result = new IabResult(IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature"); + if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); + return true; + } + + Purchase purchase = null; + try { + purchase = new Purchase(mPurchasingItemType, purchaseData, dataSignature); + String sku = purchase.getSku(); + + // Verify signature + if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { + logError("Purchase signature verification FAILED for sku " + sku); + result = new IabResult(IABHELPER_VERIFICATION_FAILED, "Signature verification failed for sku " + sku); + if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, purchase); + return true; + } + logDebug("Purchase signature successfully verified."); + } + catch (JSONException e) { + logError("Failed to parse purchase data."); + e.printStackTrace(); + result = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data."); + if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); + return true; + } + + if (mPurchaseListener != null) { + mPurchaseListener.onIabPurchaseFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase); + } + } + else if (resultCode == Activity.RESULT_OK) { + // result code was OK, but in-app billing response was not OK. + logDebug("Result code was OK but in-app billing response was not OK: " + getResponseDesc(responseCode)); + if (mPurchaseListener != null) { + result = new IabResult(responseCode, "Problem purchashing item."); + mPurchaseListener.onIabPurchaseFinished(result, null); + } + } + else if (resultCode == Activity.RESULT_CANCELED) { + logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode)); + result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled."); + if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); + } + else { + logError("Purchase failed. Result code: " + Integer.toString(resultCode) + + ". Response: " + getResponseDesc(responseCode)); + result = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response."); + if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); + } + return true; + } + + public Inventory queryInventory(boolean querySkuDetails, List moreSkus) throws IabException { + return queryInventory(querySkuDetails, moreSkus, null); + } + + /** + * Queries the inventory. This will query all owned items from the server, as well as + * information on additional skus, if specified. This method may block or take long to execute. + * Do not call from a UI thread. For that, use the non-blocking version {@link #refreshInventoryAsync}. + * + * @param querySkuDetails if true, SKU details (price, description, etc) will be queried as well + * as purchase information. + * @param moreItemSkus additional PRODUCT skus to query information on, regardless of ownership. + * Ignored if null or if querySkuDetails is false. + * @param moreSubsSkus additional SUBSCRIPTIONS skus to query information on, regardless of ownership. + * Ignored if null or if querySkuDetails is false. + * @throws IabException if a problem occurs while refreshing the inventory. + */ + public Inventory queryInventory(boolean querySkuDetails, List moreItemSkus, + List moreSubsSkus) throws IabException { + checkNotDisposed(); + checkSetupDone("queryInventory"); + try { + Inventory inv = new Inventory(); + int r = queryPurchases(inv, ITEM_TYPE_INAPP); + if (r != BILLING_RESPONSE_RESULT_OK) { + throw new IabException(r, "Error refreshing inventory (querying owned items)."); + } + + if (querySkuDetails) { + r = querySkuDetails(ITEM_TYPE_INAPP, inv, moreItemSkus); + if (r != BILLING_RESPONSE_RESULT_OK) { + throw new IabException(r, "Error refreshing inventory (querying prices of items)."); + } + } + + // if subscriptions are supported, then also query for subscriptions + if (mSubscriptionsSupported) { + r = queryPurchases(inv, ITEM_TYPE_SUBS); + if (r != BILLING_RESPONSE_RESULT_OK) { + throw new IabException(r, "Error refreshing inventory (querying owned subscriptions)."); + } + + if (querySkuDetails) { + r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreItemSkus); + if (r != BILLING_RESPONSE_RESULT_OK) { + throw new IabException(r, "Error refreshing inventory (querying prices of subscriptions)."); + } + } + } + + return inv; + } + catch (RemoteException e) { + throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while refreshing inventory.", e); + } + catch (JSONException e) { + throw new IabException(IABHELPER_BAD_RESPONSE, "Error parsing JSON response while refreshing inventory.", e); + } + } + + /** + * Listener that notifies when an inventory query operation completes. + */ + public interface QueryInventoryFinishedListener { + /** + * Called to notify that an inventory query operation completed. + * + * @param result The result of the operation. + * @param inv The inventory. + */ + public void onQueryInventoryFinished(IabResult result, Inventory inv); + } + + + /** + * Asynchronous wrapper for inventory query. This will perform an inventory + * query as described in {@link #queryInventory}, but will do so asynchronously + * and call back the specified listener upon completion. This method is safe to + * call from a UI thread. + * + * @param querySkuDetails as in {@link #queryInventory} + * @param moreSkus as in {@link #queryInventory} + * @param listener The listener to notify when the refresh operation completes. + */ + public void queryInventoryAsync(final boolean querySkuDetails, + final List moreSkus, + final QueryInventoryFinishedListener listener) { + final Handler handler = new Handler(); + checkNotDisposed(); + checkSetupDone("queryInventory"); + flagStartAsync("refresh inventory"); + (new Thread(new Runnable() { + public void run() { + IabResult result = new IabResult(BILLING_RESPONSE_RESULT_OK, "Inventory refresh successful."); + Inventory inv = null; + try { + inv = queryInventory(querySkuDetails, moreSkus); + } + catch (IabException ex) { + result = ex.getResult(); + } + + flagEndAsync(); + + final IabResult result_f = result; + final Inventory inv_f = inv; + if (!mDisposed && listener != null) { + handler.post(new Runnable() { + public void run() { + listener.onQueryInventoryFinished(result_f, inv_f); + } + }); + } + } + })).start(); + } + + public void queryInventoryAsync(QueryInventoryFinishedListener listener) { + queryInventoryAsync(true, null, listener); + } + + public void queryInventoryAsync(boolean querySkuDetails, QueryInventoryFinishedListener listener) { + queryInventoryAsync(querySkuDetails, null, listener); + } + + + /** + * Consumes a given in-app product. Consuming can only be done on an item + * that's owned, and as a result of consumption, the user will no longer own it. + * This method may block or take long to return. Do not call from the UI thread. + * For that, see {@link #consumeAsync}. + * + * @param itemInfo The PurchaseInfo that represents the item to consume. + * @throws IabException if there is a problem during consumption. + */ + void consume(Purchase itemInfo) throws IabException { + checkNotDisposed(); + checkSetupDone("consume"); + + if (!itemInfo.mItemType.equals(ITEM_TYPE_INAPP)) { + throw new IabException(IABHELPER_INVALID_CONSUMPTION, + "Items of type '" + itemInfo.mItemType + "' can't be consumed."); + } + + try { + String token = itemInfo.getToken(); + String sku = itemInfo.getSku(); + if (token == null || token.equals("")) { + logError("Can't consume "+ sku + ". No token."); + throw new IabException(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: " + + sku + " " + itemInfo); + } + + logDebug("Consuming sku: " + sku + ", token: " + token); + int response = mService.consumePurchase(3, mContext.getPackageName(), token); + if (response == BILLING_RESPONSE_RESULT_OK) { + logDebug("Successfully consumed sku: " + sku); + } + else { + logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response)); + throw new IabException(response, "Error consuming sku " + sku); + } + } + catch (RemoteException e) { + throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while consuming. PurchaseInfo: " + itemInfo, e); + } + } + + /** + * Callback that notifies when a consumption operation finishes. + */ + public interface OnConsumeFinishedListener { + /** + * Called to notify that a consumption has finished. + * + * @param purchase The purchase that was (or was to be) consumed. + * @param result The result of the consumption operation. + */ + public void onConsumeFinished(Purchase purchase, IabResult result); + } + + /** + * Callback that notifies when a multi-item consumption operation finishes. + */ + public interface OnConsumeMultiFinishedListener { + /** + * Called to notify that a consumption of multiple items has finished. + * + * @param purchases The purchases that were (or were to be) consumed. + * @param results The results of each consumption operation, corresponding to each + * sku. + */ + public void onConsumeMultiFinished(List purchases, List results); + } + + /** + * Asynchronous wrapper to item consumption. Works like {@link #consume}, but + * performs the consumption in the background and notifies completion through + * the provided listener. This method is safe to call from a UI thread. + * + * @param purchase The purchase to be consumed. + * @param listener The listener to notify when the consumption operation finishes. + */ + public void consumeAsync(Purchase purchase, OnConsumeFinishedListener listener) { + checkNotDisposed(); + checkSetupDone("consume"); + List purchases = new ArrayList(); + purchases.add(purchase); + consumeAsyncInternal(purchases, listener, null); + } + + /** + * Same as {@link consumeAsync}, but for multiple items at once. + * @param purchases The list of PurchaseInfo objects representing the purchases to consume. + * @param listener The listener to notify when the consumption operation finishes. + */ + public void consumeAsync(List purchases, OnConsumeMultiFinishedListener listener) { + checkNotDisposed(); + checkSetupDone("consume"); + consumeAsyncInternal(purchases, null, listener); + } + + /** + * Returns a human-readable description for the given response code. + * + * @param code The response code + * @return A human-readable string explaining the result code. + * It also includes the result code numerically. + */ + public static String getResponseDesc(int code) { + String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + + "3:Billing Unavailable/4:Item unavailable/" + + "5:Developer Error/6:Error/7:Item Already Owned/" + + "8:Item not owned").split("/"); + String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + + "-1002:Bad response received/" + + "-1003:Purchase signature verification failed/" + + "-1004:Send intent failed/" + + "-1005:User cancelled/" + + "-1006:Unknown purchase response/" + + "-1007:Missing token/" + + "-1008:Unknown error/" + + "-1009:Subscriptions not available/" + + "-1010:Invalid consumption attempt").split("/"); + + if (code <= IABHELPER_ERROR_BASE) { + int index = IABHELPER_ERROR_BASE - code; + if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index]; + else return String.valueOf(code) + ":Unknown IAB Helper Error"; + } + else if (code < 0 || code >= iab_msgs.length) + return String.valueOf(code) + ":Unknown"; + else + return iab_msgs[code]; + } + + + // Checks that setup was done; if not, throws an exception. + void checkSetupDone(String operation) { + if (!mSetupDone) { + logError("Illegal state for operation (" + operation + "): IAB helper is not set up."); + throw new IllegalStateException("IAB helper is not set up. Can't perform operation: " + operation); + } + } + + // Workaround to bug where sometimes response codes come as Long instead of Integer + int getResponseCodeFromBundle(Bundle b) { + Object o = b.get(RESPONSE_CODE); + if (o == null) { + logDebug("Bundle with null response code, assuming OK (known issue)"); + return BILLING_RESPONSE_RESULT_OK; + } + else if (o instanceof Integer) return ((Integer)o).intValue(); + else if (o instanceof Long) return (int)((Long)o).longValue(); + else { + logError("Unexpected type for bundle response code."); + logError(o.getClass().getName()); + throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName()); + } + } + + // Workaround to bug where sometimes response codes come as Long instead of Integer + int getResponseCodeFromIntent(Intent i) { + Object o = i.getExtras().get(RESPONSE_CODE); + if (o == null) { + logError("Intent with no response code, assuming OK (known issue)"); + return BILLING_RESPONSE_RESULT_OK; + } + else if (o instanceof Integer) return ((Integer)o).intValue(); + else if (o instanceof Long) return (int)((Long)o).longValue(); + else { + logError("Unexpected type for intent response code."); + logError(o.getClass().getName()); + throw new RuntimeException("Unexpected type for intent response code: " + o.getClass().getName()); + } + } + + void flagStartAsync(String operation) { + if (mAsyncInProgress) throw new IllegalStateException("Can't start async operation (" + + operation + ") because another async operation(" + mAsyncOperation + ") is in progress."); + mAsyncOperation = operation; + mAsyncInProgress = true; + logDebug("Starting async operation: " + operation); + } + + void flagEndAsync() { + logDebug("Ending async operation: " + mAsyncOperation); + mAsyncOperation = ""; + mAsyncInProgress = false; + } + + + int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { + // Query purchases + logDebug("Querying owned items, item type: " + itemType); + logDebug("Package name: " + mContext.getPackageName()); + boolean verificationFailed = false; + String continueToken = null; + + do { + logDebug("Calling getPurchases with continuation token: " + continueToken); + Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(), + itemType, continueToken); + + int response = getResponseCodeFromBundle(ownedItems); + logDebug("Owned items response: " + String.valueOf(response)); + if (response != BILLING_RESPONSE_RESULT_OK) { + logDebug("getPurchases() failed: " + getResponseDesc(response)); + return response; + } + if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST) + || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST) + || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) { + logError("Bundle returned from getPurchases() doesn't contain required fields."); + return IABHELPER_BAD_RESPONSE; + } + + ArrayList ownedSkus = ownedItems.getStringArrayList( + RESPONSE_INAPP_ITEM_LIST); + ArrayList purchaseDataList = ownedItems.getStringArrayList( + RESPONSE_INAPP_PURCHASE_DATA_LIST); + ArrayList signatureList = ownedItems.getStringArrayList( + RESPONSE_INAPP_SIGNATURE_LIST); + + for (int i = 0; i < purchaseDataList.size(); ++i) { + String purchaseData = purchaseDataList.get(i); + String signature = signatureList.get(i); + String sku = ownedSkus.get(i); + if (Security.verifyPurchase(mSignatureBase64, purchaseData, signature)) { + logDebug("Sku is owned: " + sku); + Purchase purchase = new Purchase(itemType, purchaseData, signature); + + if (TextUtils.isEmpty(purchase.getToken())) { + logWarn("BUG: empty/null token!"); + logDebug("Purchase data: " + purchaseData); + } + + // Record ownership and token + inv.addPurchase(purchase); + } + else { + logWarn("Purchase signature verification **FAILED**. Not adding item."); + logDebug(" Purchase data: " + purchaseData); + logDebug(" Signature: " + signature); + verificationFailed = true; + } + } + + continueToken = ownedItems.getString(INAPP_CONTINUATION_TOKEN); + logDebug("Continuation token: " + continueToken); + } while (!TextUtils.isEmpty(continueToken)); + + return verificationFailed ? IABHELPER_VERIFICATION_FAILED : BILLING_RESPONSE_RESULT_OK; + } + + int querySkuDetails(String itemType, Inventory inv, List moreSkus) + throws RemoteException, JSONException { + logDebug("Querying SKU details."); + ArrayList skuList = new ArrayList(); + skuList.addAll(inv.getAllOwnedSkus(itemType)); + if (moreSkus != null) { + for (String sku : moreSkus) { + if (!skuList.contains(sku)) { + skuList.add(sku); + } + } + } + + if (skuList.size() == 0) { + logDebug("queryPrices: nothing to do because there are no SKUs."); + return BILLING_RESPONSE_RESULT_OK; + } + + Bundle querySkus = new Bundle(); + querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuList); + Bundle skuDetails = mService.getSkuDetails(3, mContext.getPackageName(), + itemType, querySkus); + + if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) { + int response = getResponseCodeFromBundle(skuDetails); + if (response != BILLING_RESPONSE_RESULT_OK) { + logDebug("getSkuDetails() failed: " + getResponseDesc(response)); + return response; + } + else { + logError("getSkuDetails() returned a bundle with neither an error nor a detail list."); + return IABHELPER_BAD_RESPONSE; + } + } + + ArrayList responseList = skuDetails.getStringArrayList( + RESPONSE_GET_SKU_DETAILS_LIST); + + for (String thisResponse : responseList) { + SkuDetails d = new SkuDetails(itemType, thisResponse); + logDebug("Got sku details: " + d); + inv.addSkuDetails(d); + } + return BILLING_RESPONSE_RESULT_OK; + } + + + void consumeAsyncInternal(final List purchases, + final OnConsumeFinishedListener singleListener, + final OnConsumeMultiFinishedListener multiListener) { + final Handler handler = new Handler(); + flagStartAsync("consume"); + (new Thread(new Runnable() { + public void run() { + final List results = new ArrayList(); + for (Purchase purchase : purchases) { + try { + consume(purchase); + results.add(new IabResult(BILLING_RESPONSE_RESULT_OK, "Successful consume of sku " + purchase.getSku())); + } + catch (IabException ex) { + results.add(ex.getResult()); + } + } + + flagEndAsync(); + if (!mDisposed && singleListener != null) { + handler.post(new Runnable() { + public void run() { + singleListener.onConsumeFinished(purchases.get(0), results.get(0)); + } + }); + } + if (!mDisposed && multiListener != null) { + handler.post(new Runnable() { + public void run() { + multiListener.onConsumeMultiFinished(purchases, results); + } + }); + } + } + })).start(); + } + + void logDebug(String msg) { + if (mDebugLog) Log.d(mDebugTag, msg); + } + + void logError(String msg) { + Log.e(mDebugTag, "In-app billing error: " + msg); + } + + void logWarn(String msg) { + Log.w(mDebugTag, "In-app billing warning: " + msg); + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabResult.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabResult.java new file mode 100644 index 0000000..8a20158 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/IabResult.java @@ -0,0 +1,45 @@ +/* Copyright (c) 2012 Google Inc. + * + * 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.survivingwithandroid.weather.billing.util; + +/** + * Represents the result of an in-app billing operation. + * A result is composed of a response code (an integer) and possibly a + * message (String). You can get those by calling + * {@link #getResponse} and {@link #getMessage()}, respectively. You + * can also inquire whether a result is a success or a failure by + * calling {@link #isSuccess()} and {@link #isFailure()}. + */ +public class IabResult { + int mResponse; + String mMessage; + + public IabResult(int response, String message) { + mResponse = response; + if (message == null || message.trim().length() == 0) { + mMessage = IabHelper.getResponseDesc(response); + } + else { + mMessage = message + " (response: " + IabHelper.getResponseDesc(response) + ")"; + } + } + public int getResponse() { return mResponse; } + public String getMessage() { return mMessage; } + public boolean isSuccess() { return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; } + public boolean isFailure() { return !isSuccess(); } + public String toString() { return "IabResult: " + getMessage(); } +} + diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Inventory.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Inventory.java new file mode 100644 index 0000000..28969f0 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Inventory.java @@ -0,0 +1,91 @@ +/* Copyright (c) 2012 Google Inc. + * + * 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.survivingwithandroid.weather.billing.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a block of information about in-app items. + * An Inventory is returned by such methods as {@link IabHelper#queryInventory}. + */ +public class Inventory { + Map mSkuMap = new HashMap(); + Map mPurchaseMap = new HashMap(); + + Inventory() { } + + /** Returns the listing details for an in-app product. */ + public SkuDetails getSkuDetails(String sku) { + return mSkuMap.get(sku); + } + + /** Returns purchase information for a given product, or null if there is no purchase. */ + public Purchase getPurchase(String sku) { + return mPurchaseMap.get(sku); + } + + /** Returns whether or not there exists a purchase of the given product. */ + public boolean hasPurchase(String sku) { + return mPurchaseMap.containsKey(sku); + } + + /** Return whether or not details about the given product are available. */ + public boolean hasDetails(String sku) { + return mSkuMap.containsKey(sku); + } + + /** + * Erase a purchase (locally) from the inventory, given its product ID. This just + * modifies the Inventory object locally and has no effect on the server! This is + * useful when you have an existing Inventory object which you know to be up to date, + * and you have just consumed an item successfully, which means that erasing its + * purchase data from the Inventory you already have is quicker than querying for + * a new Inventory. + */ + public void erasePurchase(String sku) { + if (mPurchaseMap.containsKey(sku)) mPurchaseMap.remove(sku); + } + + /** Returns a list of all owned product IDs. */ + List getAllOwnedSkus() { + return new ArrayList(mPurchaseMap.keySet()); + } + + /** Returns a list of all owned product IDs of a given type */ + List getAllOwnedSkus(String itemType) { + List result = new ArrayList(); + for (Purchase p : mPurchaseMap.values()) { + if (p.getItemType().equals(itemType)) result.add(p.getSku()); + } + return result; + } + + /** Returns a list of all purchases. */ + List getAllPurchases() { + return new ArrayList(mPurchaseMap.values()); + } + + void addSkuDetails(SkuDetails d) { + mSkuMap.put(d.getSku(), d); + } + + void addPurchase(Purchase p) { + mPurchaseMap.put(p.getSku(), p); + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Purchase.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Purchase.java new file mode 100644 index 0000000..e915340 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Purchase.java @@ -0,0 +1,63 @@ +/* Copyright (c) 2012 Google Inc. + * + * 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.survivingwithandroid.weather.billing.util; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Represents an in-app billing purchase. + */ +public class Purchase { + String mItemType; // ITEM_TYPE_INAPP or ITEM_TYPE_SUBS + String mOrderId; + String mPackageName; + String mSku; + long mPurchaseTime; + int mPurchaseState; + String mDeveloperPayload; + String mToken; + String mOriginalJson; + String mSignature; + + public Purchase(String itemType, String jsonPurchaseInfo, String signature) throws JSONException { + mItemType = itemType; + mOriginalJson = jsonPurchaseInfo; + JSONObject o = new JSONObject(mOriginalJson); + mOrderId = o.optString("orderId"); + mPackageName = o.optString("packageName"); + mSku = o.optString("productId"); + mPurchaseTime = o.optLong("purchaseTime"); + mPurchaseState = o.optInt("purchaseState"); + mDeveloperPayload = o.optString("developerPayload"); + mToken = o.optString("token", o.optString("purchaseToken")); + mSignature = signature; + } + + public String getItemType() { return mItemType; } + public String getOrderId() { return mOrderId; } + public String getPackageName() { return mPackageName; } + public String getSku() { return mSku; } + public long getPurchaseTime() { return mPurchaseTime; } + public int getPurchaseState() { return mPurchaseState; } + public String getDeveloperPayload() { return mDeveloperPayload; } + public String getToken() { return mToken; } + public String getOriginalJson() { return mOriginalJson; } + public String getSignature() { return mSignature; } + + @Override + public String toString() { return "PurchaseInfo(type:" + mItemType + "):" + mOriginalJson; } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Security.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Security.java new file mode 100644 index 0000000..f0ef526 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/Security.java @@ -0,0 +1,123 @@ +/* Copyright (c) 2012 Google Inc. + * + * 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.survivingwithandroid.weather.billing.util; + +import android.text.TextUtils; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + + +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; + +/** + * Security-related methods. For a secure implementation, all of this code + * should be implemented on a server that communicates with the + * application on the device. For the sake of simplicity and clarity of this + * example, this code is included here and is executed on the device. If you + * must verify the purchases on the phone, you should obfuscate this code to + * make it harder for an attacker to replace the code with stubs that treat all + * purchases as verified. + */ +public class Security { + private static final String TAG = "IABUtil/Security"; + + private static final String KEY_FACTORY_ALGORITHM = "RSA"; + private static final String SIGNATURE_ALGORITHM = "SHA1withRSA"; + + /** + * Verifies that the data was signed with the given signature, and returns + * the verified purchase. The data is in JSON format and signed + * with a private key. The data also contains the {@link PurchaseState} + * and product ID of the purchase. + * @param base64PublicKey the base64-encoded public key to use for verifying. + * @param signedData the signed JSON string (signed, not encrypted) + * @param signature the signature for the data, signed with the private key + */ + public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) { + if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) || + TextUtils.isEmpty(signature)) { + Log.e(TAG, "Purchase verification failed: missing data."); + return false; + } + + PublicKey key = Security.generatePublicKey(base64PublicKey); + return Security.verify(key, signedData, signature); + } + + /** + * Generates a PublicKey instance from a string containing the + * Base64-encoded public key. + * + * @param encodedPublicKey Base64-encoded public key + * @throws IllegalArgumentException if encodedPublicKey is invalid + */ + public static PublicKey generatePublicKey(String encodedPublicKey) { + try { + byte[] decodedKey = Base64.decode(encodedPublicKey); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM); + return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } catch (InvalidKeySpecException e) { + Log.e(TAG, "Invalid key specification."); + throw new IllegalArgumentException(e); + } catch (Base64DecoderException e) { + Log.e(TAG, "Base64 decoding failed."); + throw new IllegalArgumentException(e); + } + } + + /** + * Verifies that the signature from the server matches the computed + * signature on the data. Returns true if the data is correctly signed. + * + * @param publicKey public key associated with the developer account + * @param signedData signed data from server + * @param signature server signature + * @return true if the data and signature match + */ + public static boolean verify(PublicKey publicKey, String signedData, String signature) { + Signature sig; + try { + sig = Signature.getInstance(SIGNATURE_ALGORITHM); + sig.initVerify(publicKey); + sig.update(signedData.getBytes()); + if (!sig.verify(Base64.decode(signature))) { + Log.e(TAG, "Signature verification failed."); + return false; + } + return true; + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "NoSuchAlgorithmException."); + } catch (InvalidKeyException e) { + Log.e(TAG, "Invalid key specification."); + } catch (SignatureException e) { + Log.e(TAG, "Signature exception."); + } catch (Base64DecoderException e) { + Log.e(TAG, "Base64 decoding failed."); + } + return false; + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SkuDetails.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SkuDetails.java new file mode 100644 index 0000000..266c19e --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SkuDetails.java @@ -0,0 +1,58 @@ +/* Copyright (c) 2012 Google Inc. + * + * 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.survivingwithandroid.weather.billing.util; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Represents an in-app product's listing details. + */ +public class SkuDetails { + String mItemType; + String mSku; + String mType; + String mPrice; + String mTitle; + String mDescription; + String mJson; + + public SkuDetails(String jsonSkuDetails) throws JSONException { + this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails); + } + + public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException { + mItemType = itemType; + mJson = jsonSkuDetails; + JSONObject o = new JSONObject(mJson); + mSku = o.optString("productId"); + mType = o.optString("type"); + mPrice = o.optString("price"); + mTitle = o.optString("title"); + mDescription = o.optString("description"); + } + + public String getSku() { return mSku; } + public String getType() { return mType; } + public String getPrice() { return mPrice; } + public String getTitle() { return mTitle; } + public String getDescription() { return mDescription; } + + @Override + public String toString() { + return "SkuDetails:" + mJson; + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SwABillingUtil.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SwABillingUtil.java new file mode 100644 index 0000000..447c8f4 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/billing/util/SwABillingUtil.java @@ -0,0 +1,73 @@ +package com.survivingwithandroid.weather.billing.util; + +import android.app.Activity; +import android.content.Context; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.PopupWindow; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import com.survivingwithandroid.weather.R; + +/** + * Created by Francesco on 21/02/14. + */ +public class SwABillingUtil { + + public static String KEY = "Your_key_here"; + private static String SKU_DONATE_W2 = "SKU_IN_APP"; + //private static String SKU_DONATE_W2 = "android.test.purchased"; + + + public static void showDonateDialog(final Context ctx, final IabHelper mHelper, final Activity act) { + LayoutInflater inf = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View v = inf.inflate(R.layout.popdonate_layout, null, false); + + final PopupWindow pw = new PopupWindow(v); + pw.setWidth(RelativeLayout.LayoutParams.WRAP_CONTENT); + pw.setHeight(RelativeLayout.LayoutParams.WRAP_CONTENT); + + Button canBtn = (Button) v.findViewById(R.id.btnCancelDonate); + + + canBtn.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + pw.dismiss(); + } + }); + + final Button donBtn = (Button) v.findViewById(R.id.btnDonate); + donBtn.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + String payload="test"; + + mHelper.launchPurchaseFlow(act, SKU_DONATE_W2, 2000, + new IabHelper.OnIabPurchaseFinishedListener() { + @Override + public void onIabPurchaseFinished(IabResult result, Purchase info) { + if (result.isFailure()) { + Log.i("SwA", "Failure = " + result); + //Toast.makeText(getActivity(), "Error purchasing: " + result, Toast.LENGTH_LONG).show(); + return; + } else if (info.getSku().equals(SKU_DONATE_W2)) { + donBtn.setClickable(false); + Toast.makeText(ctx, "Thank you!", Toast.LENGTH_LONG).show(); + } + } + }, payload); + pw.dismiss(); + + } + }); + + pw.showAtLocation(v, Gravity.CENTER, 0, 0); + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/CityResult.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/CityResult.java new file mode 100644 index 0000000..8ec9f77 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/CityResult.java @@ -0,0 +1,60 @@ +package com.survivingwithandroid.weather.model; + +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public class CityResult { + + private String woeid; + private String cityName; + private String country; + + public CityResult() {} + + public CityResult(String woeid, String cityName, String country) { + this.woeid = woeid; + this.cityName = cityName; + this.country = country; + } + + public String getWoeid() { + return woeid; + } + + public void setWoeid(String woeid) { + this.woeid = woeid; + } + + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + @Override + public String toString() { + return cityName + "," + country; + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/Weather.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/Weather.java new file mode 100644 index 0000000..f7beaa6 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/model/Weather.java @@ -0,0 +1,76 @@ +package com.survivingwithandroid.weather.model; +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public class Weather { + + public String imageUrl; + + public Condition condition = new Condition(); + public Wind wind = new Wind(); + public Atmosphere atmosphere = new Atmosphere(); + public Forecast forecast = new Forecast(); + public Location location = new Location(); + public Astronomy astronomy = new Astronomy(); + public Units units = new Units(); + + public String lastUpdate; + + public class Condition { + public String description; + public int code; + public String date; + public int temp; + } + + public class Forecast { + public int tempMin; + public int tempMax; + public String description; + public int code; + } + + public static class Atmosphere { + public int humidity; + public float visibility; + public float pressure; + public int rising; + } + + public class Wind { + public int chill; + public int direction; + public int speed; + } + + public class Units { + public String speed; + public String distance; + public String pressure; + public String temperature; + } + + public class Location { + public String name; + public String region; + public String country; + } + + public class Astronomy { + public String sunRise; + public String sunSet; + } + +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/IWeatherImageProvider.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/IWeatherImageProvider.java new file mode 100644 index 0000000..4e0d922 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/IWeatherImageProvider.java @@ -0,0 +1,30 @@ +package com.survivingwithandroid.weather.provider; + +import android.graphics.Bitmap; + +import com.android.volley.RequestQueue; + +/* + * Copyright (C) 2014 (Francesco Azzola) - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public interface IWeatherImageProvider { + + public Bitmap getImage(int code,RequestQueue requestQueue, WeatherImageListener listener); + + + public static interface WeatherImageListener { + public void onImageReady(Bitmap image); + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/WeatherImageProvider.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/WeatherImageProvider.java new file mode 100644 index 0000000..851215b --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/WeatherImageProvider.java @@ -0,0 +1,45 @@ +package com.survivingwithandroid.weather.provider; + + +import android.graphics.Bitmap; + +import com.android.volley.RequestQueue; +import com.android.volley.Response; +import com.android.volley.toolbox.ImageRequest; + +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ + // We retrieve the image from YAHOO! Weather, but you can use any kind of image provider you like + +public class WeatherImageProvider implements IWeatherImageProvider { + private static final String YAHOO_IMG_URL = "http://l.yimg.com/a/i/us/we/52/"; + + @Override + public Bitmap getImage(int code, RequestQueue requestQueue, final WeatherImageListener listener) { + String imageURL = YAHOO_IMG_URL + code + ".gif"; + ImageRequest ir = new ImageRequest(imageURL, new Response.Listener() { + + @Override + public void onResponse(Bitmap response) { + if (listener != null) + listener.onImageReady(response); + } + }, 0, 0, null, null); + + requestQueue.add(ir); + return null; + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/YahooClient.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/YahooClient.java new file mode 100644 index 0000000..281dec6 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/provider/YahooClient.java @@ -0,0 +1,239 @@ +package com.survivingwithandroid.weather.provider; + +import android.content.Context; +import android.util.Log; + +import com.android.volley.Request; +import com.android.volley.RequestQueue; +import com.android.volley.Response; +import com.android.volley.VolleyError; +import com.android.volley.toolbox.StringRequest; +import com.android.volley.toolbox.Volley; +import com.survivingwithandroid.weather.Config; +import com.survivingwithandroid.weather.MainActivity; +import com.survivingwithandroid.weather.model.CityResult; +import com.survivingwithandroid.weather.model.Weather; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public class YahooClient { + public static String YAHOO_GEO_URL = "http://where.yahooapis.com/v1"; + public static String YAHOO_WEATHER_URL = "http://weather.yahooapis.com/forecastrss"; + + private static String APPID = "APP_ID_KEY"; + + public static List getCityList(String cityName) { + List result = new ArrayList(); + HttpURLConnection yahooHttpConn = null; + try { + String query =makeQueryCityURL(cityName); + //Log.d("Swa", "URL [" + query + "]"); + yahooHttpConn= (HttpURLConnection) (new URL(query)).openConnection(); + yahooHttpConn.connect(); + XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); + parser.setInput(new InputStreamReader(yahooHttpConn.getInputStream())); + Log.d("Swa", "XML Parser ok"); + int event = parser.getEventType(); + + CityResult cty = null; + String tagName = null; + String currentTag = null; + + // We start parsing the XML + while (event != XmlPullParser.END_DOCUMENT) { + tagName = parser.getName(); + + if (event == XmlPullParser.START_TAG) { + if (tagName.equals("place")) { + // place Tag Found so we create a new CityResult + cty = new CityResult(); + // Log.d("Swa", "New City found"); + } + currentTag = tagName; + // Log.d("Swa", "Tag ["+tagName+"]"); + } + else if (event == XmlPullParser.TEXT) { + // We found some text. let's see the tagName to know the tag related to the text + if ("woeid".equals(currentTag)) + cty.setWoeid(parser.getText()); + else if ("name".equals(currentTag)) + cty.setCityName(parser.getText()); + else if ("country".equals(currentTag)) + cty.setCountry(parser.getText()); + + // We don't want to analyze other tag at the moment + } + else if (event == XmlPullParser.END_TAG) { + if ("place".equals(tagName)) + result.add(cty); + } + + event = parser.next(); + } + } + catch(Throwable t) { + t.printStackTrace(); + // Log.e("Error in getCityList", t.getMessage()); + } + finally { + try { + yahooHttpConn.disconnect(); + } + catch(Throwable ignore) {} + + } + return result; + } + + public static void getWeather(String woeid, String unit, RequestQueue rq, final WeatherClientListener listener) { + String url2Call = makeWeatherURL(woeid, unit); + // Log.d("SwA", "Weather URL ["+url2Call+"]"); + final Weather result = new Weather(); + StringRequest req = new StringRequest(Request.Method.GET, url2Call, new Response.Listener() { + @Override + public void onResponse(String s) { + parseResponse(s, result); + listener.onWeatherResponse(result); + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError volleyError) { + + } + }); + + rq.add(req); + } + + private static Weather parseResponse (String resp, Weather result) { + // Log.d("SwA", "Response ["+resp+"]"); + try { + XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); + parser.setInput(new StringReader(resp)); + + String tagName = null; + String currentTag = null; + + int event = parser.getEventType(); + boolean isFirstDayForecast = true; + while (event != XmlPullParser.END_DOCUMENT) { + tagName = parser.getName(); + + if (event == XmlPullParser.START_TAG) { + if (tagName.equals("yweather:wind")) { + // Log.d("SwA", "Tag [Wind]"); + result.wind.chill = Integer.parseInt(parser.getAttributeValue(null, "chill")); + result.wind.direction = Integer.parseInt(parser.getAttributeValue(null, "direction")); + result.wind.speed = (int) Float.parseFloat(parser.getAttributeValue(null, "speed")); + } + else if (tagName.equals("yweather:atmosphere")) { + // Log.d("SwA", "Tag [Atmos]"); + result.atmosphere.humidity = Integer.parseInt(parser.getAttributeValue(null, "humidity")); + result.atmosphere.visibility = Float.parseFloat(parser.getAttributeValue(null, "visibility")); + result.atmosphere.pressure = Float.parseFloat(parser.getAttributeValue(null, "pressure")); + result.atmosphere.rising = Integer.parseInt(parser.getAttributeValue(null, "rising")); + } + else if (tagName.equals("yweather:forecast")) { + // Log.d("SwA", "Tag [Fore]"); + if (isFirstDayForecast) { + result.forecast.code = Integer.parseInt(parser.getAttributeValue(null, "code")); + result.forecast.tempMin = Integer.parseInt(parser.getAttributeValue(null, "low")); + result.forecast.tempMax = Integer.parseInt(parser.getAttributeValue(null, "high")); + isFirstDayForecast = false; + } + } + else if (tagName.equals("yweather:condition")) { + // Log.d("SwA", "Tag [Condition]"); + result.condition.code = Integer.parseInt(parser.getAttributeValue(null, "code")); + result.condition.description = parser.getAttributeValue(null, "text"); + result.condition.temp = Integer.parseInt(parser.getAttributeValue(null, "temp")); + result.condition.date = parser.getAttributeValue(null, "date"); + } + else if (tagName.equals("yweather:units")) { + // Log.d("SwA", "Tag [units]"); + result.units.temperature = "°" + parser.getAttributeValue(null, "temperature"); + result.units.pressure = parser.getAttributeValue(null, "pressure"); + result.units.distance = parser.getAttributeValue(null, "distance"); + result.units.speed = parser.getAttributeValue(null, "speed"); + } + else if (tagName.equals("yweather:location")) { + result.location.name = parser.getAttributeValue(null, "city"); + result.location.region = parser.getAttributeValue(null, "region"); + result.location.country = parser.getAttributeValue(null, "country"); + } + else if (tagName.equals("image")) + currentTag = "image"; + else if (tagName.equals("url")) { + if (currentTag == null) { + result.imageUrl = parser.getAttributeValue(null, "src"); + } + } + else if (tagName.equals("lastBuildDate")) { + currentTag="update"; + } + else if (tagName.equals("yweather:astronomy")) { + result.astronomy.sunRise = parser.getAttributeValue(null, "sunrise"); + result.astronomy.sunSet = parser.getAttributeValue(null, "sunset"); + } + + } + else if (event == XmlPullParser.END_TAG) { + if ("image".equals(currentTag)) { + currentTag = null; + } + } + else if (event == XmlPullParser.TEXT) { + if ("update".equals(currentTag)) + result.lastUpdate = parser.getText(); + } + event = parser.next(); + } + + } + catch(Throwable t) { + t.printStackTrace(); + } + + return result; + } + + private static String makeQueryCityURL(String cityName) { + // We remove spaces in cityName + cityName = cityName.replaceAll(" ", "%20"); + return YAHOO_GEO_URL + "/places.q(" + cityName + "%2A);count=" + Config.MAX_CITY_RESULT + "?appid=" + APPID; + } + + private static String makeWeatherURL(String woeid, String unit) { + return YAHOO_WEATHER_URL + "?w=" + woeid + "&u=" + unit; + } + + + /* Pubblic listener interface */ + + public static interface WeatherClientListener { + public void onWeatherResponse(Weather weather); + } +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/CityFinderActivity.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/CityFinderActivity.java new file mode 100644 index 0000000..dd27af7 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/CityFinderActivity.java @@ -0,0 +1,152 @@ +package com.survivingwithandroid.weather.settings; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.NavUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.Filter; +import android.widget.Filterable; +import android.widget.TextView; + +import com.survivingwithandroid.weather.R; +import com.survivingwithandroid.weather.model.CityResult; +import com.survivingwithandroid.weather.provider.YahooClient; + +import java.util.ArrayList; +import java.util.List; + +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public class CityFinderActivity extends Activity { + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.cityfinder_layout); + AutoCompleteTextView edt = (AutoCompleteTextView) this.findViewById(R.id.edtCity); + CityAdapter adpt = new CityAdapter(this, null); + edt.setAdapter(adpt); + getActionBar().setDisplayHomeAsUpEnabled(true); + + edt.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + CityResult result = (CityResult) parent.getItemAtPosition(position); + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(CityFinderActivity.this); + //Log.d("SwA", "WOEID [" + result.getWoeid() + "]"); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString("woeid", result.getWoeid()); + editor.putString("cityName", result.getCityName()); + editor.putString("country", result.getCountry()); + editor.commit(); + NavUtils.navigateUpFromSameTask(CityFinderActivity.this); + } + }); + + } + + private class CityAdapter extends ArrayAdapter implements Filterable { + + private Context ctx; + private List cityList = new ArrayList(); + + public CityAdapter(Context ctx, List cityList) { + super(ctx, R.layout.cityresult_layout, cityList); + this.cityList = cityList; + this.ctx = ctx; + } + + + @Override + public CityResult getItem(int position) { + if (cityList != null) + return cityList.get(position); + + return null; + } + + @Override + public int getCount() { + if (cityList != null) + return cityList.size(); + + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View result = convertView; + + if (result == null) { + LayoutInflater inf = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + result = inf.inflate(R.layout.cityresult_layout, parent, false); + + } + + TextView tv = (TextView) result.findViewById(R.id.txtCityName); + tv.setText(cityList.get(position).getCityName() + "," + cityList.get(position).getCountry()); + + return result; + } + + @Override + public long getItemId(int position) { + if (cityList != null) + return cityList.get(position).hashCode(); + + return 0; + } + + @Override + public Filter getFilter() { + Filter cityFilter = new Filter() { + + + @Override + protected FilterResults performFiltering(CharSequence constraint) { + FilterResults results = new FilterResults(); + if (constraint == null || constraint.length() < 2) + return results; + + List cityResultList = YahooClient.getCityList(constraint.toString()); + results.values = cityResultList; + results.count = cityResultList.size(); + return results; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + cityList = (List) results.values; + notifyDataSetChanged(); + } + }; + + return cityFilter; + } + } + + +} diff --git a/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/WeatherPreferenceActivity.java b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/WeatherPreferenceActivity.java new file mode 100644 index 0000000..5c9bc6f --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/java/com/survivingwithandroid/weather/settings/WeatherPreferenceActivity.java @@ -0,0 +1,61 @@ +package com.survivingwithandroid.weather.settings; + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.survivingwithandroid.weather.R; +import com.survivingwithandroid.weather.model.CityResult; + +import java.util.List; +/* + * Copyright (C) 2014 Francesco Azzola - Surviving with Android (http://www.survivingwithandroid.com) + * + * 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. + */ +public class WeatherPreferenceActivity extends PreferenceActivity { + + + @Override + public void onCreate(Bundle Bundle) { + super.onCreate(Bundle); + getActionBar().setDisplayHomeAsUpEnabled(true); + String action = getIntent().getAction(); + + addPreferencesFromResource(R.xml.weather_prefs); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + // We set the current values in the description + Preference prefLocation = getPreferenceScreen().findPreference("swa_loc"); + Preference prefTemp = getPreferenceScreen().findPreference("swa_temp_unit"); + + prefLocation.setSummary(getResources().getText(R.string.summary_loc) + " " + prefs.getString("cityName", null) + "," + prefs.getString("country", null)); + + String unit = prefs.getString("swa_temp_unit", null) != null ? "°" + prefs.getString("swa_temp_unit", null).toUpperCase() : ""; + prefTemp.setSummary(getResources().getText(R.string.summary_temp) + " " + unit); + + + //getPreferenceScreen().findPreference("swa_temp_unit").setDefaultValue(valTemp); + //getPreferenceScreen().findPreference("swa_system").setDefaultValue(unitSys); + + + } + + + + + + +} diff --git a/AndroidYahooWeather/weather/src/main/res/drawable-hdpi/ic_launcher.png b/AndroidYahooWeather/weather/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b44ccc80f3e9d02a0960303cf736c2e4d5b710 GIT binary patch literal 7721 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 literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/drawable-mdpi/ic_launcher.png b/AndroidYahooWeather/weather/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a1bf709d3b4cedf0fd8b53454ee1e339b9e6c7cd GIT binary patch literal 3769 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 P00000NkvXXu0mjf3bfbd literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/drawable-xxhdpi/ic_launcher.png b/AndroidYahooWeather/weather/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b7df51b1eecbfb447f9966b979f2f5bd6285bb87 GIT binary patch literal 24654 zcmaG{^;;9{*WX5Lj2hiAx5z~HX{EcnyOoqKX{iTz`Thg% zb=~pnIrpj0i91q5O#vH94g~-J*l!eNwO;P{|7{5R%eg22rwITsCwe0*rQ`MMI1Bui z(0<`>R+egQZPLGQt8b#9C5jVolA}RUsG72b4D^YpZ}2lH8Cl<;Cc~j6Y5gIjJm4|c zG2t%|Y0oU5wZ^iHu=LeO8_!cNA8vt8zEz0(tnRb_#K#Grvd>FZc}{i|zrq^+zw3Ej z5NSb^KzbaoHI+cl0NzA{ggq~{Fa6Ql>sdOSMQ6Ka9`7KnfK>;iZs>16nLrlXE-dm! zhZ}$9y;C6SEbS~g`~8f5`%D8;JY%n^HU2Q3J@eUF?I}-z>%>9*+rSUucV%y@O#XR- z{yqe&k`1r>VG{fL{B3u>t={|j?VIy5jasFCz1nK-qvZAj2&XFVWc})c>Bkigw^i0J zmq(MvJuQ61o@H@llk6Y#o-loQ!X9N{*Hn)25dmsc1{-g>6!brns0iQx`tC8v*_u7? zG+=VhuFHo?WHbZnt}>fn6!jN#cYnq{I};TtQdwjv*X%6uN|mU63Sykg68vrE*E1CE z8~5MXy6FC~)Q{&h?CwgSk^lG__;b~Re{4|SBgY*X@aAL1%;S%}&6FJmuV-}l(JTSg z&*Fw>yUVh+`4Z6vm6PmQX*v4e=JVX)o0Gygz^l{cq1F@@73+j&K5}QzA|bjV+ zBoU=2V3zD{|e8U9A3IKmsdakfFiF^>dnET%_yr!jQtD~ zd*0NM#{qn(?!Q-SR&7zxKmNv2ChD|STjn&ga1o5o_TSC$KVVdHXbD?;m76_xa<(i| zM1)p*3CMbej!JrdM*gSooRV(i6>1O43-8^y&M2F-A?6%m3b4?10!R*G*;UR%V zeCwx6>3F|qkaML>*Xiw^FED5lw=*-T`Y8MHq`r8Z)+Y2yvj0i%IM~NE+^cVNM;lw7kvjq9a9*t_#IZ+`H(n*Q*_jeFpx>s3mc6DC$hy zMC;DDxKmz;2Sefbk?(#H%r4q-o3v;?xb}CynR5T2^gEQ21!f{;#}z~s#Ao7;iZMPjYt-R^8S^ z{0cjMNyN!y;-PTeW3e`wKzS?;CX_=`y>i}jq-;^Vem8{n<949T>FNYLpA90*A&uV) z=gC(q<4wu?;aHgy>SY zeFFAJEjvz;1uIsO8F9n81&e-4f2+~D_U!qO$3Kp0cUuKd*>On!70th2Jy+KHNiL|e z^;%wDzH@hjOe;rfM(00)<^XVJr^t&^5+l^GVCk5CJa*-Y}yvkB@9l2Iz;v>-4GIwl6h+m z9&9O+`Q2*oa#l|yZH2)(S=`lOo0Kjd$C>8TsG1(5ud-e#%6BK_@olF^H{9vnS>z(`0z0EX=vPhpFa9K;eY8|D=ibxDrD zDZU*98NtH`O&CEjF^bG8dUM!AYz?wj``6nsB+>@N@Zg@PLqxy~%#-|OmljVZ&^GeW z3hYEB*j0*CC-w~l!R43a2|n>uNmpG|m5m`$4RKIQr~WBoiLX8VK7X=&3Wj*b+bMm% zr48|agjhzKBBcNMu%`nR z@RYqW`4L84a!lfE&RW#M=mHM7QQ+9A4CV%Hqou;~F(I0*Luf#^AcED{mv;kMV}eap zLm#;-%-6M*moA4upVs(-e>AF?&w5zdJie1L_;OHjpSF20A``~S_<*HjCqjVrFb|V` z22Os&B{mcfFD&CSh@ICV)>H8}_{42)ns?})TiFbjvP1g4LJOVJk$w7ssk?*n`I~7; z7r!3XDV#=XSiWh7r=HQO(7e#HkY3F7mh{W{D+mGznF3u&NkHP6LEAXCaxe0=MYSWQ zJjn!xum7S&2&Q#ZSWFTqFI}7S9yd9lr}da$ViPQR&8OKn@st+-+m@X!6Abow$BBL& z$|)aUExIeCyWIK4dkJljqN?jexbP$ZQ+U;xRzCt=-yIA}XRZqxDP-LvW}7s*;>M*V zpVh}N)8v(hX6zHTsdm*7$Dj-2(^JwKi@|#|y?bEUun=Yl4L3|YUXm@IyNHKdXcCT) z))%_&MpJVi4=Xse>DhdZ3vL>~|uGuny)&se;& zHx`lmbYm6~lFi{!(&n`GyKMe`RKS)7p38W(ZDtM;%nwqjd9?PN-*CCqSqav)r(=N4L~^|wLfhktE$(Xu zt_0BL2SI{nuY+SCllRI45ZJjC0T5`(_WLTd-=~fYb>D7+X}tg7np{gJd;dA{KK^%- z`SU7~!M+l6Zr6VOy1ushAu+%l<@03_Z&6n?oXWP zz+b7$xo;k1WlRnON-yGF{__$wc={VO#C=On@aZ3re62Me-o|oap@x}d$LLO^t=8%y zk$Fg4w176@2aykT37!=%T=~?Ca;oMxigwm@mS4ILWrMy^*4HrksnvD=hgX*};7SyN zvjyIh>zGIY_B`=>A&Zd<9NTC%B&KI(sBX*lDa#k692`#vgp z=RtV0)Q-7nAqA}NW0Yrn zh59+&^UU-XK<&STz9&+!x%5D0@M>Hxeq}@D)K^7@8WIL(OCpi}!->bibJC7V?kx1! zjY%{}FwR?4;d!}f5YA5N%}0XM=@ux%Z6k9un_hKVP2aNxX#M-UXX5wlG{1Tv=VEno z=O)_ZnhA0u+jeU80bN8=Ec6TRVoy=+2MzBbfFAW!=nSz5s-kjor<`(fyHu@cv(a^1 zuJo`7~$3hFiqu=V`0p-NC?!jMqzROct zj;0h8d?8E;e=`<<>(uE&KO!@;7-;)%yH8ud6!C5-aX^pDT+yHK#7Zfm~4J z%wb)66YtKbvJxS&myg4LHYMZ_U_pOU|52G3$zyNp%K3ZuiE{$y$5wUs+b^;0*Thtx z53qc446K?R(OQSyx_cvCj$Ikr_FE#rU%F-b$|k{^#!Z)>C@4Q~gCDYgbp?_X&V9;v zy`6WA7M>e?vHk;0owVM!l%HQIV5uI>E<<7n*d{o1C>56coYC*8d{hh@bUYf?;AaNC z1EXIJTn!Pu!XND%8^geraWeXom{7qOQ)K&~vPHijcxXKj(BFDxzWj-EXte^kd?b)| zRWFjil){!ZEeHJ`xa>ymt1Gx2>R)}2^-yvb)*rF!^XcQu1A2RJr#L(RR#xBb`bc7P zN?+klZ7}scXcxR&bs6~TxcLP1+RQOD_UGX3htu!=TYr!ITn=5y#ix8|mbD66pG)b{ zzphN$bO-LK&7soBa?5DV1lsydM^!(UCXr_N#o0u4+jkrxH?im>mgLiWl8 z_-VzCxYfeKE{UuDRH^e@CZ<_7-ITkXFzwRFV2ykv1@LF3f=?tATJtlvOK_{YsI zZFSn9zGLr*)B9Fp_n1iRk9HllfsD0yb*pMY-_$*Ozy0)a+1rs2a%YBqTFJyPc2*tG zu~IHCY>%Uyy0RRO8ED+Wpec;X=nuL`>r;V_t%Xza-)K6O{DHX~<57yD+KQCLVyhZ{ z`v;nyw;0}@ z0&KM3b&B^vnM|BR@8_hD?mk<3Z1jkWMdEj(oFtHFe{s|)N%P!c&W_qW$4+}6mm6_g zn@K-gi%Tj|n};8)?jAlzoZ4Jt=D#^VVqH<`N1wyh!c<94Ud5#KgpCfo;0ZM9V|xQ5 zb-A6YycGP%)ti%&fCEg+kcWIS-SWFw@nZgcSAT|X>DnFgppPEp{MRV9ylA#3WZEU7 z??4V}shPrS{NN4rlB!E1<(VB(XB){o0qG; zAJ~CCTeJG&8Z1+m-LhiF7mGCO?ORm3s-<0~PBU|Y{KE@5h_eMC>L(bWI6NIH0a+xI zRDXA*M#DNl>0iFZTHcqkg7CAdgt)V9r)+>Q1vBE)7OJ920m?a1S^n8OXb*JU$1_S`INS8pzsAi?Zk{QxHF@txxucnw)C!*l(?(lClX^=*(^tXR`q4bmrN83m zPm0Q!9N+Tw^As@h8+y_K1Wc;CDw$`Of?!U~7NIGL0wmga@ufOhijM7p-RqW)%@Q$! zFZR_>7&^^>KA0F(`vfYR5Y89j5c4P=FS(e5i_H(hvgyOB%CI+u`7uUts{ko~XBB2E z;)>G46>vAF2d}=zl@;QqUw@9*Dn|)&)7|_7^2P&QP0_zsiT-9jmnt(#@%(#$cJanw z{e#u4%LgR_@9@_q*=+CI?85AaAy)XF4k0@=cqX|F)tiYJMI88PEnMe;T_%DGX|O`} z3i4`;NDYJhe1k|Uf(&ylIXpg=V4EclYzI>bl8fj zQI$K2o>`1he6=Z`?6L>;BF~ue2m- zb1i1_SiV{29keNp|6qu;|=u^3+$ibzW= zec$pF5NXqYUBULv*_`g0`wp~s5J0-;O+O>ttLbW46k^Yn6Y(Z6$nIvQ zwdH#)e_j-?e7N7=yD@pjl>AS!iR1jnEb~^2g}FVT_HW-ijJzO8~q5(_18o3BhX7Ex^?u_d+{P;EfVA<#%Iy5g!K(S0K zbSY&7W>^BCRUQm<&d1^tH7NVNAoI(;rl2RMPqp8F>dHhc|GDE>)M}@bG_&IiA2zDp z#x2vc0MKqWvwo<7h!L@@u!y(K=# zCc@?1B1CG}h2c*$#+sXJSwMyGJQ$P0@r?v5bKa@%=#16DQqs%onsvFiM|)`n4AaeF zQoWMkK-fFX!<*%a@b$_OD(Q5x9Qw!&N8tfxO}%YG7REXcngjDK{y#qX68}{hu0L&8 zVoCorcE5NHAPE>^fEMK=|L~f0sKux>gVmuM`#ZQ5d)QZCj3G zboJA5p5!adRDW<`_^F$?Z{txn8*~FP<{L?xDp=-iwS3qutW6YJx+%nmP6e^taqOzmVKzp<>g&?a=ftSB-` z9&cJ1c31#?GhYTTkwxmUNZs@gMc~>&M*beym0WB~R+wWHueRY`=C}v(kkrZz3s6&-CG*JD< zkuod9{0i+Z13`zA&!fO}4Gt@>U{K}Nq}20Zn&QpUrAlmoW!sn-sQKdRQaf>Z*t?$D zxveQsDSLXTn7xO@llOfsmGy^Ap<>i-njh%Cqx{lA;9H_cy}gGyK9K{{8EE0^xowZVzpt z-+wzDLK`U>3yvjC8)Qrjnv_wL{@F_{1D#kT3zbt!YGQN?bhp2v<7&~UIFc&%$+}j2 zZJG@30i%WD=JQhW@BBa~d~cMk-9KG?26Isy$%%Oq;;<(N3x{SqdZagcH$oTM=L$f;&u5xCO-wOOQyEY$gdI(w5${N ze_anxvr?x$=+;*B_NU1=HL+PS%Q>zInEto$&vbOwey?G@dP&b`1`b>2FJL!bdNU}6 zfmbQEZG?=Y)xBL~!Qo@( zDDJYaS=H)=r}f?$d`EAbDyQBiO8N7T?u%sdlgnXU5pnzamfN56a?iQJDbYA45ggLa zQaDD2U#O{dqV;r&QSRM;RVMaXgzQyGNh0+=ZcGWykPzng`f0L~*~Ld5UTITj)Cffw z`OEu#G9T{9dNdxMK{GiuievO?XDZ^vRxv&-5iw{;eJ?%7t7?#0(2x3kA9;g6PeMH% z_2cif+p<4M_ct0SR5I~Vdak+5?{6`f=H5HUyVd;n_rG1muhV&^WfU!``AWx}Gzn+d zjz%ayJB%Ou*bE=H*-DArn7m}?u|%(rnz&bU#lLonZRG0ESgw4KI!nF%z~Y4!G>S`$ zb4CSHr$xy|5U&vTcMX5Awe$Xf;X`fI8*40>^^I%Uq};K-x>Cse&UQ^UDNBy}wUGW+ zYXoJmeS)$oF1J$MU(;l}{tzZ(o)^bQ%d1Y3pXwm}HeG~4-=S;fx}~nxxXB8Xe9Qz+ z)5Qk$913#DCAfR|;i_avZSq`}4PF#@66}wb&Mk>Ch6pk)X^O7E(Tcp`jr^+?tE^z@U4G#&iNm zH8>&HR)jpdXaw1hWmx6*6^&xC+I&xf+UAb6D--Z8tx*w8jBdV*Pl>24f4-Ypp5Q;U zU$Eq|&^%T8_&7odcRLQ1IrL5;CmjqYUo31FTzzn(hKCD=R{x+rdg~pO$LX(El{-16 z4NeWuuo3yyn0)YVpXTjN48VJSlSh8jhgAHZaeU$vy8N4Gz)TIj`B;-?ZiyIibPTq6 zSq!VtSPhbFf~j(>c=UCeYSLF;Uh;nqZsJ1~9`Xl_K6R}}Y824Ml`8zd&5}uKuw%b% zMUp_z|LoKk4;0yh+U!UEB~3Jba(0UmAuuk}qKW5UaMXy2IGdj>qH*e2_E;RYd6roe zZ9QEMSn^oZoAVu1t2_FOWplG?SoQGNamnL1hS`RST?>Dfq0eV%b5t5^{YSgK$9uYq zKRq8)9800~(f5xX;E$;^e#CAkeY2!C55fT!Qb}liDTh*s8a8SUVN@%A(qGX4rzB@7 z!y546Mg|SkfDCLKIf%JnluikS! ztu=95)UD{l>DNhS_@Az3NuP5%zB1inFS>ulU%(T-U?v87WNhW!*^?Q zOS3sC>8rHG?Tf`6uxNYb44>pIKOcp-8bVChC&Rjs{7w)2R4yZmYG>C>rbF*of&U_F7fPbD)Z3 zoi@Kkd*Dye$}c`*0K)Q0N#P-qIbU* zzi|mWt_K7>ec9qB;Z?}K!+iZVTUzS-~z zn*U*0JYfx#`Qx~en<4WjNOE~Mm8W>_q3&bPs7XbSXe!5@p~JPEV2Z}gjs4g7nZfei zZT$t^;zsDc_|{$AhF>vMQmuk`2}y5CT*vrdmp0qPt}AmY>1$&QYb+CVDwTrSg*7#6 zv+erVFf?4dBILcxX^W;JA+ZwIrhOH*{PBd9OjzTZmSS7mMknp^9Pq($MV{luXIG>_ zy?J=&dz{G`qxyjN?}z_lSpWOpXdU;p#5xY=hnn6oeTO;SX98c>Rv6OB`YDvuQkALH zNS9EzV(7MbWc}hT9f`P8#sJMi&RNn=A@hcSan__pYeuU12-;qAPIae^4P{ZGg;yl8 z?H+-_+%~!Hzq=+{t@~G?3tOVDI{O371;p`cT->v`xZ;cUEZZ3=-0A#Mk_B7k;ky*4?f5 zy2sIUP1vH2oh1bsVk-0;Z%p&NRv{PrIu!K!>l&ukHk?J9TKbX@UZa6$smC&_^dynDAqY0=l@N0@q@k_AdWYmEsz(y0piFc#u1_twuH5p`{J|Mv^Z0vf&$sgJB8Bstt@-lUe_j9z<9DU}+%eY; zVp_jZR&(pCm1g3cpUVVAZ>xs?ySg~Jr%}3jZ+=(NtK*hs=cZ+P9f{%I{)HngaXDvv zk$E<-S{(P-{Fy-Er4|@DAxaal1!Wf9?Jf1BcG+!zoq2E(R%`N7b>9J>tYR+xzVUik zqp_mRJb4STUAyZo#gPVa9B*9u9GDJ@B1McvFX_Q4^kpIkGOT_osg9t%IeUe3#~6 zlnOTS9&2y@cj#EpTy?(i7Y*Gkd8Q2EXq`*dWc^F!cuAN^4@zMu;GhaH9Thi5UQI;f zxAGagC1-0yH&p6igfQ3sLoi|PFTZT^9Z_3`-4B@&0ZmHI^1)>+wVK#V`@zg6maEJi z(&>?0Qpg%uu3~z4Ey)N2h3f2WO9!K=U~6|Br)}^D+b3cHj>vjBxz@To>q?x8rAnE} z;xc$UHHgrVUepG`&Q{~7>6u~jkbh))Vsq^B;EmZ*qbAQQICGBWaAi?qlv>=g%RbBF z$Wyen=)1IW<7B?oZ(p_9!~frE=`HEP)YQa%w1+K|l}I+0$G+ry^)y<_zAAFibySv~#14)8!pYwijDMw*9utBd=o0wx*mZ{4#L80GdI~@ces_#9MB_M#pv&~$ z-k9PythWOr<#z+4RIzO2>)*7>r6>NFUo_aw4!+x@%~l8(WUn3ey%xdAO)2Z?;{V=_ zJ$0yuTVJ!AeomO{!6qG|m^__}?s(PR`^nU`IAOq07^G9d04;iPFJMdX((D#g6@wUQG$~_7-Bj@;)QafW?VEoOoG$wURwcpB&Teur zag9F$Qw?m8M>w9^;+uRmZ=I0W@S95mX?UR0ZsZ?EVCdAR_muSxKtl0iqEN#4M{r?` z=^^qS_^H{<8oCw_lAj&fXdiQ&ex+sbhzrUFF#V_@_mxMHK$GZe za*4ETAX|uaDZcaIEmJh3gN3<-Ltp-zPxONi{Ui3beZx6X9F*KDKc$ch4!q4Jg4SXo zEVu`+@pP>oR4Ebj90*`3L_-L~Z>Mcg&W*-mivpe!K`o))?1rx{TzNQFVTQktuZlY6 zf5%j&_=YfEf>^b1EGZqckT05&sKe>Ki3nZof^Wcp(Q53NJWcUILc6uy(|Pc#I7eb%B*&7i3&>A83)$A`4+lo3!tN?do%Cu9Rk`WmxvJ8paSWv z9fv@zUyLLQCetTfpp>^sPvl8$D5PTWJ&0Q+J(6P^08R4eo%PfSOPFUtEpd@Gs`qv< z`k|(9FTyzUZ}7b;6^pE~VZ>Kj+3k?FKzMcDWfDt%W6Przi6Lt$L?`agE(RoodfQoM zeW4K0Y|MW~^;4N5nL)McAn1!fI5sq_kR?%?MTnxlZ$o2ebD_h_OYu+%aUID$c%@qg z)eP->E|GC5BFBW0?;8S9b2SO!>t5bYIbQvvo1=qY?g2CT_Ut*q%+7qEx`gDv8CT6i z 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 aH;J87;OhU_1HbWwSen|H6dm@w@_zs)=+i;~ literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/ic_menu_refresh.png b/AndroidYahooWeather/weather/src/main/res/drawable/ic_menu_refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..e13315f5da34487cba048540f41fed1b14706180 GIT binary patch literal 2025 zcmVC5uat znCKD`O-rn~1e*Zqs>mQ}`-uB+M>R(3R zlib`te&>14^PcCt=e)rGV>;-+0-Qh)5FpSjs7Z{CvL*lm=`p~+%N;0k3FQAB~;fiEXcjqTHpih17fuZ2@p7ejxB^>xb*~`Y)Dl zHy_egQYrkH#5jM#7wqn2`0g8H-2BRlcK#z^#>_%EMFD3 z`2J4N69g;lJ6(RP{y^|M0Iv{aI#%Hv7lg0pj4%8pXY=lwBUTGoFkZ^e%^kwUznT+)Xokh1pSN;eP&-buI}tVlL1U}xUwN!yQk^6MM~X2fjUG&0S%6 z<^8k}DnG9S7(n5eDdKq=@~Y{66SX@`sT_bhZ4B=l0F){SL-&TbKY-j~Qa}NLPnM!| zy#x%T>D@Gjeq|H!T;p-xDj5KF!^Q>6XGV>*>DtDaUCc#^pzyCIFc85l8{+^|fs1Bd zYECg$V;4+l(BawL_-J;s^Ax}|j52_Mh{|M;UKDy(MeFu;9RZ)J6Tis(el1^{JrDWk zfCT9R0OF+bQ?W3EAY;AO0S7uxOBiqE)YMr51`xHUo?oU^RE;x75niGK3=wpLrfnE! zI8WplBcI@|d-m)qWRZn~5yY0N;CTZjD;MVkNv{oJ2GBzH-36)+(2Fn^nyMM{+6 z4KX78_=`RvHIAAI&6~{kmLQiKD{r+t8!X{0nK-NL$ePi<9GwNOOb_R9ZYw?q4GaSk zfDQ?UE`*kH-$wt8I!PXwsI6h;J{_J3N1mF(U|&qaTY!MTsFz=Px~`I3lnP5Il)_Io z>NqS9O~$Kd2n2Zm2ezX1M-}zTCIfG&_agcY2a2!=K~Oheuv(NNaZfCRI3=G+#fO3e z2>>7qhnU5&FC-s1T>A_uHaIJP635M0zaP2fWj+A|NN2L6s)ao$FbE8t&iP1tJWV@zi6>i5aO79Za8?!&-wMM;KR$8P1_Ry3CQWyBPBYf&h*#4 zJJQ!FH{cuAttvDPuWhJ*xqLTyNNX#j}1qrrfhV96GPZ1bT1 zNiQH*$*p1=1(-dDBnxp09g)c^HD}}5B)LWJgPc9s?{;RQ9&};_2|zKZO6>&z9XbF8 zv$9Epj)eTFeI%+bE${Y{i8<*hs^BSwbi{)W7W6tAu~o7HGhBeDuQLgP0Y`RvFUGFj zwl0P)mt^}3z!xDPg;Yc-NP2}1-uBazp(o8pWi@o35t*W1{hDqi> z4HhIIFw$eLz-u`8nbu>Eo@hBy>#tnzYtkx&q?n3&z3yP#4P(G}P3<2SXE8JYc1OPk@2IE8dH<=*@WB0VyMVrVXACSQpcJE_>Y_H;s7&G zssH)-CmXOH6R?zbhyVZpC3HntbYx+4WjbSWWnpw>05UK!F)c7LEiyP%GBP?eH##*l zEigDbFfgP}a>)Py03~!qSaf7zbY(hiZ)9m^c>ppnF)=MLF)cDUR5CI;G&edmGc7PU zIxsNR6Uub}000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o00000NkvXX Hu0mjfQR<0n literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_blue.xml b/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_blue.xml new file mode 100644 index 0000000..0543949 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_blue.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_green.xml b/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_green.xml new file mode 100644 index 0000000..b2357a9 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_green.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_red.xml b/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_red.xml new file mode 100644 index 0000000..b0e2db6 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/drawable/line_shape_red.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/moon.png b/AndroidYahooWeather/weather/src/main/res/drawable/moon.png new file mode 100644 index 0000000000000000000000000000000000000000..640a4e7057a11f21488fe31e53f8b2fb2fa89fde GIT binary patch literal 1977 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 literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/sun.png b/AndroidYahooWeather/weather/src/main/res/drawable/sun.png new file mode 100644 index 0000000000000000000000000000000000000000..495e0c52d2eb4b1fc3fcca3a5ecb7fe6255988e2 GIT binary patch literal 11254 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 Al>h($ literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/temperature.png b/AndroidYahooWeather/weather/src/main/res/drawable/temperature.png new file mode 100644 index 0000000000000000000000000000000000000000..9bf9453abe931d7a9c5e7f2dc7ee664c38836584 GIT binary patch literal 2551 zcmeHJ`8(TL7ym|5Ql_@2Dy^}Nb&7^kTBMYSr3ZMJ*BawuxFN9TYVT zZMB2qjcCUd8jx-8^0ulw0I;*h6MgJ#!ac!gP}aS; zy*=M}B34tZR(zF(mZ>%U&R_b75;#?XYKpe_=7L;;8Nv)NzSLL5oNTrE=HmLX9Ad6| zXzpf)ardh{y_>KM>;k4fKvLefMJ#+mT&BF#6rM#6f#B95jlzMc#5hEv&B+p`V#g;JmEDjETfq2AODD>F)QqQs;a4+ut?AB$k zqD29+(khmaDiS7%N7%PggmA<{5!aRzrHvIIj(L{cN*14{zuQ~uw{TOxEE6)JjC-YV zQ^;OIl4}3pN`8IOjL?&_{QLHws8uIy2NJ7*xCX;btv8=GsgwHYV-OHTN|bk^tvngX zY8RwM2;q)eP-g(cvm~v}E??gD-3plsYHrPToPYy)2ne8V062%j0FNvH$WR0HtmFVg z3_yPMf9L<&BOor&>2%#3-qjgOh257|0b-yvE*ld@DH7(3xpNkmNCE z2MqAb4uol)x4b=V(}!i2qDvqFbt@@2>3%k}oW{*3HvW~TB~OY{+^0#S5A(zs^Yf425{T=ab5;p4FdU4@8cN0CLvqI&u=x1X z413g|-~dmzZAVlV@OvN3L`uW(LCkt{doBNmaAB`^{AXrD4ovGG8$EHn?x6J zjRwDd90ybWHfND=rB%u2Og3gR)S71!=_@X{6N}!z!tCpF`Vj@I!vJ27uytjAyAy-^ zi`YT(_XmUvqe@CjeQqk9X8G$H(~Y-Z3WwH$H)&^sl1`ZJmGe0W-t*q5#XPa+3pX6> z7cp$JB`?PvroUk-ts-aoer;`+$U4#&S90Q8q-VscH51C^=-VzK{cG4wTI|D*G8Zwt zHOqlado*}4$V>xez-7%@Xl1pK)yI{~4fkub*mu50){cz_YoO$+;m(l>#X(_o$6N+K zLD5H!5h&n$z5XL>%<6=+orU%HKdjnj;IIgI;X*5(9Zc-1FIv}NYdHg6ouf|LZ5KW< z`Mzwe7rx}Hz4(}xB;k>1N$Pn1yNB9fD@0;c-hyRZ?HQ|1*6c7WlCW3Nxo>g+Sj^K^ zw+`uyfs_PDJq+%A{r-B6|L%gBh5~JfX$H1$)$84oZ<<18=mcv{&EF01su-Bx zbnjQGBwn^5cEk|~1fxU+KQ*$tRrSc94ed%xu0c&T{A_GmA$S(a2t?kUzr=R1{cx^~ zv~isTtw$du>7;N2=mD}jEeEo64*G8`Z6?pEd+M~okdw;g$(x_7I$ZiiY*+cYW~}$Q zjLeQ$xbx09`_h7>I2dFxtZhn$r<>kqD z>-r`J6bG`}z~!NpXA845LDpFGy>vV&u6ppgULt%bmjhryA1YyZKOfHBy%NzRD8oxjzz!k|W%azBI7C)!YHUo#iDrCB&m#w3br_Wz zL@wmzU~TA8bv2u-pVJk}QbIig zSv0;mvCL|~)^m`NDsUrO6mcu2Qtjwanv7v;i*mHHBbr`4`cE?vc;;*`gZ@=FGSBJc QByERyx}8ElalzgAFDo)J3jhEB literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/drawable/wind.png b/AndroidYahooWeather/weather/src/main/res/drawable/wind.png new file mode 100644 index 0000000000000000000000000000000000000000..da56fd761472f838cd1edcbcdab35fee7d0f4763 GIT binary patch literal 6728 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 E13B?RqW}N^ literal 0 HcmV?d00001 diff --git a/AndroidYahooWeather/weather/src/main/res/layout-land/fragment_main.xml b/AndroidYahooWeather/weather/src/main/res/layout-land/fragment_main.xml new file mode 100644 index 0000000..4e3f78d --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/layout-land/fragment_main.xml @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AndroidYahooWeather/weather/src/main/res/layout/activity_main.xml b/AndroidYahooWeather/weather/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..3899cab --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/layout/activity_main.xml @@ -0,0 +1,25 @@ + + + diff --git a/AndroidYahooWeather/weather/src/main/res/layout/cityfinder_layout.xml b/AndroidYahooWeather/weather/src/main/res/layout/cityfinder_layout.xml new file mode 100644 index 0000000..4b3b7b8 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/layout/cityfinder_layout.xml @@ -0,0 +1,43 @@ + + + + + + + + + + diff --git a/AndroidYahooWeather/weather/src/main/res/layout/cityresult_layout.xml b/AndroidYahooWeather/weather/src/main/res/layout/cityresult_layout.xml new file mode 100644 index 0000000..2a40909 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/layout/cityresult_layout.xml @@ -0,0 +1,27 @@ + + + + + + + \ No newline at end of file diff --git a/AndroidYahooWeather/weather/src/main/res/layout/fragment_main.xml b/AndroidYahooWeather/weather/src/main/res/layout/fragment_main.xml new file mode 100644 index 0000000..7a4cad9 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/layout/fragment_main.xml @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AndroidYahooWeather/weather/src/main/res/layout/popdonate_layout.xml b/AndroidYahooWeather/weather/src/main/res/layout/popdonate_layout.xml new file mode 100644 index 0000000..049b405 --- /dev/null +++ b/AndroidYahooWeather/weather/src/main/res/layout/popdonate_layout.xml @@ -0,0 +1,54 @@ + + + + + + + +