Added Pepper Farm Simulator sample and updated the README.md.
|
@ -1,7 +1,9 @@
|
|||
Payment One APK
|
||||
===============
|
||||
|
||||
Simple demonstration application to show how to have Nokia IAP and Google IAB in same application
|
||||
Simple example application demonstrating how to utilise both Nokia In-App
|
||||
Payment and Google In-App Billing in the same application. The resulting APK
|
||||
will run in both Nokia X and Google Android devices.
|
||||
|
||||
Building with Eclipse
|
||||
---------------------
|
||||
|
@ -13,13 +15,13 @@ Building with Eclipse
|
|||
Building with Gradle wrapper
|
||||
----------------------------
|
||||
|
||||
###### Linux & OS X
|
||||
**Linux & OS X**
|
||||
|
||||
```
|
||||
$ ./gradlew installDebug
|
||||
```
|
||||
|
||||
###### Windows
|
||||
**Windows**
|
||||
|
||||
```
|
||||
C:\PaymentOneAPK> gradlew installDebug
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||
<classpathentry kind="lib" path="libs/android-support-v13.jar"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="gen"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Pepper Farm Simulator Aidl</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
<project>NokiaInappPaymentLib</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.nokia.example.pepperfarm.client"
|
||||
android:versionCode="1"
|
||||
android:versionName="Prod" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="11"
|
||||
android:targetSdkVersion="16" />
|
||||
<uses-permission android:name="com.nokia.payment.BILLING"/>
|
||||
|
||||
<application
|
||||
android:name="Pepperfarm"
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/launchicon"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity android:name="PepperFarmSplashScreen"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="ProductListActivity"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PRODUCT_LIST" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="PepperFarmMainScreenActivity"></activity>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,68 @@
|
|||
Nokia In-App Payment API sample: Pepper Farm Simulator
|
||||
======================================================
|
||||
|
||||
This Nokia sample application demonstrates how to implement the support for
|
||||
Nokia In-App Payment enabler. This application contains sample code to:
|
||||
|
||||
* Connect to Nokia In-App Payment enabler service
|
||||
* Check if your application supports In-App billing
|
||||
* Return product information
|
||||
* Purchase content
|
||||
* Consume content
|
||||
* Restore content
|
||||
|
||||
|
||||
Instructions
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Import the project to your IDE. The recommended build target for the project is
|
||||
Android 4.1.2, API level 16.
|
||||
|
||||
|
||||
Implementation
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Description of the classes:
|
||||
|
||||
* Package `com.nokia.example.pepperfarm.client`:
|
||||
* `MainScreenPepperListFragment`: Fragment for the main screen of the
|
||||
Pepper Farm Simulator. Contains all purchased peppers in a list.
|
||||
* `PepperFarmMainScreenActivity`: This is the first screen that loads in the
|
||||
Pepper Farm application. It shows you a list of peppers you have already
|
||||
purchased and includes buttons allowing you to purchase, restore and
|
||||
consume peppers.
|
||||
* `PepperFarmSplashScreen`: Splash screen that is shown when application is
|
||||
launched for the first time.
|
||||
* `ProductListActivity`: Activity representing a list of purchasable products.
|
||||
* `ProductListFragment`: Fragment containing a list of all purchasable peppers.
|
||||
|
||||
* Package `com.nokia.example.pepperfarm.client.util`:
|
||||
* `ProductDetails`: Holds product details response data.
|
||||
* `Purchase`: Holds purchase and restoration response data.
|
||||
|
||||
* Package `com.nokia.example.pepperfarm.iap`:
|
||||
* `Payment`: This class creates a `ServiceConnection` with Nokia In-App
|
||||
Payment enabler. Used to do all Nokia In-App Payment enabler specific
|
||||
actions.
|
||||
|
||||
* Package `com.nokia.example.pepperfarm.product`:
|
||||
* `Config`: Product ID mapping for all purchasable content.
|
||||
* `Content`: Used to represent a collection of Nokia Store IAP items.
|
||||
|
||||
* Package `com.nokia.example.pepperfarm.product.adapters`:
|
||||
* `ContentListAdapter`: An adapter used to show a list of Peppers you
|
||||
currently own.
|
||||
* `ContentPurchaseAdapter`: This adapter is used to display a list of
|
||||
products that can be purchased.
|
||||
|
||||
|
||||
Known issues
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
License
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
See the separate license file provided with this project.
|
|
@ -0,0 +1,49 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.7.+'
|
||||
}
|
||||
}
|
||||
apply plugin: 'android'
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: '*.jar')
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 16
|
||||
buildToolsVersion "18.1.1"
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
runProguard false
|
||||
proguardFile getDefaultProguardFile('proguard-android.txt')
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
java.srcDirs = ['src']
|
||||
resources.srcDirs = ['src']
|
||||
aidl.srcDirs = ['src']
|
||||
renderscript.srcDirs = ['src']
|
||||
res.srcDirs = ['res']
|
||||
assets.srcDirs = ['assets']
|
||||
}
|
||||
|
||||
// Move the tests to tests/java, tests/res, etc...
|
||||
instrumentTest.setRoot('tests')
|
||||
|
||||
// Move the build types to build-types/<type>
|
||||
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
|
||||
// This moves them out of them default location under src/<type>/... which would
|
||||
// conflict with src/ being used by the main source set.
|
||||
// Adding new build types or product flavors should be accompanied
|
||||
// by a similar customization.
|
||||
debug.setRoot('build-types/debug')
|
||||
release.setRoot('build-types/release')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#Wed Feb 05 15:41:42 EET 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip
|
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
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 "$@"
|
|
@ -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
|
После Ширина: | Высота: | Размер: 53 KiB |
|
@ -0,0 +1,40 @@
|
|||
Copyright © 2014 Nokia Corporation. All rights reserved.
|
||||
|
||||
Nokia, Nokia Developer, and HERE are trademarks and/or registered trademarks of
|
||||
Nokia Corporation. Other product and company names mentioned herein may be
|
||||
trademarks or trade names of their respective owners.
|
||||
|
||||
License
|
||||
Subject to the conditions below, you may use, copy, modify and/or merge copies
|
||||
of this software and associated content and documentation files (the “Software”)
|
||||
to test, develop, publish, distribute, sub-license and/or sell new software
|
||||
derived from or incorporating the Software, solely in connection with Nokia
|
||||
devices. Some of the documentation, content and/or software maybe licensed under
|
||||
open source software or other licenses. To the extent such documentation,
|
||||
content and/or software are included, licenses and/or other terms and conditions
|
||||
shall apply in addition and/or instead of this notice. The exact terms of the
|
||||
licenses, disclaimers, acknowledgements and notices are reproduced in the
|
||||
materials provided, or in other obvious locations. No other license to any other
|
||||
intellectual property rights is granted herein.
|
||||
|
||||
This file, unmodified, shall be included with all copies or substantial portions
|
||||
of the Software that are distributed in source code form.
|
||||
|
||||
The Software cannot constitute the primary value of any new software derived
|
||||
from or incorporating the Software.
|
||||
|
||||
Any person dealing with the Software shall not misrepresent the source of the
|
||||
Software.
|
||||
|
||||
Disclaimer
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE, QUALITY AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES (INCLUDING,
|
||||
WITHOUT LIMITATION, DIRECT, SPECIAL, INDIRECT, PUNITIVE, CONSEQUENTIAL,
|
||||
EXEMPLARY AND/ OR INCIDENTAL DAMAGES) OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Nokia Corporation retains the right to make changes to this document at any
|
||||
time, without notice.
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
</lint>
|
|
@ -0,0 +1,20 @@
|
|||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# 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 *;
|
||||
#}
|
|
@ -0,0 +1,15 @@
|
|||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system edit
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
#
|
||||
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-16
|
||||
android.library=false
|
После Ширина: | Высота: | Размер: 550 B |
После Ширина: | Высота: | Размер: 13 KiB |
После Ширина: | Высота: | Размер: 19 KiB |
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:startColor="#D5DDE0"
|
||||
android:centerColor="#e7e7e8"
|
||||
android:endColor="#CFCFCF"
|
||||
android:angle="270" />
|
||||
</shape>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:startColor="#D5DDE0"
|
||||
android:centerColor="#e7e7e8"
|
||||
android:endColor="#CFCFCF"
|
||||
android:angle="270" />
|
||||
</shape>
|
После Ширина: | Высота: | Размер: 13 KiB |
После Ширина: | Высота: | Размер: 5.7 KiB |
После Ширина: | Высота: | Размер: 9.9 KiB |
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_selected="false"
|
||||
android:state_pressed="false"
|
||||
android:drawable="@drawable/gradient_background" />
|
||||
<item android:state_pressed="true"
|
||||
android:drawable="@drawable/gradient_background_on_hover" />
|
||||
<item android:state_selected="true"
|
||||
android:state_pressed="false"
|
||||
android:drawable="@drawable/gradient_background_on_hover" />
|
||||
</selector>
|
После Ширина: | Высота: | Размер: 15 KiB |
После Ширина: | Высота: | Размер: 8.0 KiB |
После Ширина: | Высота: | Размер: 107 KiB |
После Ширина: | Высота: | Размер: 507 KiB |
После Ширина: | Высота: | Размер: 6.4 KiB |
После Ширина: | Высота: | Размер: 7.7 KiB |
После Ширина: | Высота: | Размер: 6.3 KiB |
После Ширина: | Высота: | Размер: 9.9 KiB |
После Ширина: | Высота: | Размер: 5.4 KiB |
После Ширина: | Высота: | Размер: 9.9 KiB |
После Ширина: | Высота: | Размер: 6.7 KiB |
После Ширина: | Высота: | Размер: 4.3 KiB |
После Ширина: | Высота: | Размер: 507 KiB |
После Ширина: | Высота: | Размер: 9.7 KiB |
После Ширина: | Высота: | Размер: 13 KiB |
После Ширина: | Высота: | Размер: 9.4 KiB |
После Ширина: | Высота: | Размер: 3.1 KiB |
После Ширина: | Высота: | Размер: 7.4 KiB |
После Ширина: | Высота: | Размер: 10 KiB |
После Ширина: | Высота: | Размер: 6.0 KiB |
После Ширина: | Высота: | Размер: 507 KiB |
После Ширина: | Высота: | Размер: 20 KiB |
После Ширина: | Высота: | Размер: 32 KiB |
После Ширина: | Высота: | Размер: 18 KiB |
После Ширина: | Высота: | Размер: 7.8 KiB |
После Ширина: | Высота: | Размер: 14 KiB |
После Ширина: | Высота: | Размер: 23 KiB |
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 507 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<fragment
|
||||
android:id="@+id/product_list"
|
||||
android:name="com.nokia.example.pepperfarm.client.ProductListFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/get_new_peppers_link"
|
||||
tools:context=".ProductListActivity"
|
||||
tools:layout="@android:layout/list_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/get_new_peppers_link"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:text="@string/new_peppers"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="5dip" >
|
||||
<!-- ListRow Left side Thumbnail image -->
|
||||
<LinearLayout
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginRight="5dip"
|
||||
android:padding="3dip" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/list_image"
|
||||
android:layout_width="60dip"
|
||||
android:layout_height="60dip"
|
||||
android:contentDescription="@string/app_name"
|
||||
android:src="@drawable/farm"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
<!-- Rightend Arrow -->
|
||||
|
||||
<!-- IAP Name -->
|
||||
|
||||
<Button
|
||||
android:id="@+id/start_purchase"
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:text="Buy" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iapName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toLeftOf="@+id/start_purchase"
|
||||
android:layout_toRightOf="@+id/thumbnail"
|
||||
android:text="@string/appname"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/product_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@+id/iapName"
|
||||
android:layout_below="@+id/iapName"
|
||||
android:layout_toLeftOf="@+id/start_purchase"
|
||||
android:text="@string/product_description"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/price"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@+id/product_description"
|
||||
android:layout_toLeftOf="@+id/start_purchase"
|
||||
android:text="@string/price"
|
||||
android:textSize="15sp" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawSelectorOnTop="false" />
|
||||
|
||||
<TextView android:id="@android:id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="No peppers"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/get_new_peppers_link"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/get_new_peppers_underline"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/fetching_peppers_progressbar"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fetching_peppers_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/get_restorables"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/buy_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginRight="14dp"
|
||||
android:text="@string/buy_peppers" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/your_peppers"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@+id/buy_button"
|
||||
android:layout_alignBottom="@+id/buy_button"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:text="@string/owned_peppers"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/product_list"
|
||||
android:name="com.nokia.example.pepperfarm.client.MainScreenPepperListFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@+id/fetch_restorable_products"
|
||||
android:layout_below="@+id/buy_button"
|
||||
class="com.nokia.example.pepperfarm.client.MainScreenPepperListFragment"
|
||||
tools:layout="@layout/pepper_list_row_view" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/reset_purchases"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:text="@string/reset_purchase" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/fetch_restorable_products"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@+id/reset_purchases"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:text="@string/fetch_all_restorables" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" >
|
||||
|
||||
<ImageView android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:src="@drawable/splashscreen"
|
||||
android:contentDescription="@string/splash_screen_description"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="5dip" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pepper_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@+id/pepperName"
|
||||
android:layout_below="@+id/pepperName"
|
||||
android:layout_toLeftOf="@+id/eat_pepper"
|
||||
android:lines="2"
|
||||
android:text="@string/pepper_description"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/eat_pepper"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingTop="10dp"
|
||||
android:text="@string/consume_pepper" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/list_image"
|
||||
android:layout_width="120dip"
|
||||
android:layout_height="120dip"
|
||||
android:layout_alignRight="@+id/pepperName"
|
||||
android:layout_below="@+id/pepper_description"
|
||||
android:contentDescription="@string/pepper_name"
|
||||
android:src="@drawable/farm"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemcount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@+id/pepperName"
|
||||
android:layout_alignBottom="@+id/pepperName"
|
||||
android:layout_toRightOf="@+id/pepperName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pepperName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@+id/eat_pepper"
|
||||
android:layout_alignBottom="@+id/eat_pepper"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_toLeftOf="@+id/eat_pepper"
|
||||
android:text="@string/pepper_name"
|
||||
android:textSize="20sp" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -0,0 +1,11 @@
|
|||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 11+. This theme completely replaces
|
||||
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo">
|
||||
<!-- API 11 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -0,0 +1,12 @@
|
|||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 14+. This theme completely replaces
|
||||
AppBaseTheme from BOTH res/values/styles.xml and
|
||||
res/values-v11/styles.xml on API 14+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo">
|
||||
<!-- API 14 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -0,0 +1,11 @@
|
|||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
</resources>
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<resources>
|
||||
<string name="app_name">Pepper Farm Simulator</string>
|
||||
<string name="title_product_detail">Product Detail</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="appname">appName</string>
|
||||
<string name="price">price</string>
|
||||
<string name="your_peppers">Your Items</string>
|
||||
<string name="buy_peppers">Buy Peppers!</string>
|
||||
<string name="pepper_name">Pepper Name</string>
|
||||
<string name="pepper_description">Pepper Description</string>
|
||||
<string name="eat_pepper">Consume Pepper</string>
|
||||
<string name="splash_screen_description">Pepper Farm Simulator Splash Screen</string>
|
||||
<string name="product_description">Product description</string>
|
||||
<string name="no_peppers">No peppers</string>
|
||||
<string name="reset_purchase">Reset purchases</string>
|
||||
<string name="owned_peppers">Your peppers</string>
|
||||
<string name="new_peppers">New peppers</string>
|
||||
<string name="consume_pepper">Consume</string>
|
||||
<string name="get_new_peppers_string">Get New Peppers</string>
|
||||
<string name="get_new_peppers_underline"><u>Get New Peppers</u></string>
|
||||
<string name="pepper_farm">Pepper Farm</string>
|
||||
<string name="pepper_seeds">Pepper Seeds</string>
|
||||
<string name="jalapeno">Jalapeno</string>
|
||||
<string name="sweet_bell">Sweet Bell</string>
|
||||
<string name="habenero">Habenero</string>
|
||||
<string name="pepper_spray">Pepper Spray</string>
|
||||
<string name="pepper_farm_description">Your Pepper Farm. Use it to grow new peppers.</string>
|
||||
<string name="pepper_seeds_description">A good start to a farm.</string>
|
||||
<string name="jalapeno_description">Looking for something a little more spicy? Try the Jalapeno.</string>
|
||||
<string name="sweet_bell_description">Jumpstart your farm with a Sweet Bell</string>
|
||||
<string name="habenero_description">A good middle ground.</string>
|
||||
<string name="pepper_spray_description">Keep the bears away.</string>
|
||||
<string name="get_restorables">Fetching owned peppers</string>
|
||||
<string name="fetch_all_restorables">Fetch restorable products</string>
|
||||
</resources>
|
|
@ -0,0 +1,24 @@
|
|||
<!--
|
||||
Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
See the license text file delivered with this project for more information.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -0,0 +1,190 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
import com.nokia.example.pepperfarm.product.Content.Product;
|
||||
import com.nokia.example.pepperfarm.product.adapters.ContentListAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This is the Fragment for the main screen of the Pepper Farm Simulator.
|
||||
* Mostly it's job is to set up the ContentListAdapter which does the real work of determining how to
|
||||
* display the list of purchased products.
|
||||
*/
|
||||
public class MainScreenPepperListFragment extends ListFragment {
|
||||
|
||||
|
||||
public static TextView getpeppers;
|
||||
public static View fetch_peppers_progressbar;
|
||||
public static TextView fetching_peppers;
|
||||
|
||||
/**
|
||||
* The fragment's current callback object, which is notified of list item
|
||||
* clicks.
|
||||
*/
|
||||
private Callbacks mCallbacks = sDummyCallbacks;
|
||||
public static MainScreenPepperListFragment reference;
|
||||
|
||||
private final static String LOG_TAG = MainScreenPepperListFragment.class.getCanonicalName();
|
||||
|
||||
/**
|
||||
* The adapter used to display the list of peppers that have already been purchased.
|
||||
*/
|
||||
public ArrayAdapter<Product> adapter;
|
||||
|
||||
/**
|
||||
* A callback interface that all activities containing this fragment must
|
||||
* implement. This mechanism allows activities to be notified of item
|
||||
* selections.
|
||||
*/
|
||||
public interface Callbacks {
|
||||
/**
|
||||
* Callback for when an item has been selected.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
public void onItemSelected(String id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A dummy implementation of the {@link Callbacks} interface that does
|
||||
* nothing. Used only when this fragment is not attached to an activity.
|
||||
*/
|
||||
private static Callbacks sDummyCallbacks = new Callbacks() {
|
||||
@Override
|
||||
public void onItemSelected(String id) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public MainScreenPepperListFragment() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders a Fragment representing one pepper in the list that has already been purchased by the user.
|
||||
* Also is responsible for updating the list
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
reference = this;
|
||||
List<Product> purchasedItems = Content.getPurchasedItems();
|
||||
|
||||
if (purchasedItems.isEmpty()) {
|
||||
//We need to display some text saying you have no peppers.
|
||||
adapter = new ContentListAdapter(getActivity(), R.layout.pepper_list_row_view, purchasedItems);
|
||||
setListAdapter(adapter);
|
||||
} else {
|
||||
adapter = new ContentListAdapter(getActivity(), R.layout.pepper_list_row_view, purchasedItems);
|
||||
setListAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
fetching_peppers = (TextView) view.findViewById(R.id.fetching_peppers_text);
|
||||
fetch_peppers_progressbar = view.findViewById(R.id.fetching_peppers_progressbar);
|
||||
//Get new peppers linkbutton
|
||||
getpeppers = (TextView) view.findViewById(R.id.get_new_peppers_link);
|
||||
getpeppers.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent("android.intent.action.PRODUCT_LIST");
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.main_screen_pepper_list_fragment, container, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for error checking to make sure that any Activity attaching to this fragment properly supports
|
||||
* Callbacks.
|
||||
*/
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
// Activities containing this fragment must implement its callbacks.
|
||||
if (!(activity instanceof Callbacks)) {
|
||||
throw new IllegalStateException(
|
||||
"Activity must implement fragment's callbacks.");
|
||||
}
|
||||
|
||||
mCallbacks = (Callbacks) activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
|
||||
// Reset the active callbacks interface to the dummy implementation.
|
||||
mCallbacks = sDummyCallbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the activity that an item has been selected.
|
||||
*/
|
||||
@Override
|
||||
public void onListItemClick(ListView listView, View view, int position,
|
||||
long id) {
|
||||
super.onListItemClick(listView, view, position, id);
|
||||
|
||||
// Notify the active callbacks interface (the activity, if the
|
||||
// fragment is attached to one) that an item has been selected.
|
||||
mCallbacks.onItemSelected(Content.ITEMS.get(position).productId);
|
||||
}
|
||||
|
||||
/**
|
||||
* On resume of this Fragment, we need to refresh the list of peppers available to the user.
|
||||
* This is because peppers could have been bought and the view may not have an updated list of purchased peppers.
|
||||
* This is a little inefficient but simple enough for demonstration purposes. If you had a large list of items to display,
|
||||
* you may want to consider having a listener that gets updated when items are purchased. The listener could then update the adapter
|
||||
* only when items are purchased or consumed.
|
||||
*/
|
||||
@Override
|
||||
public void onResume() {
|
||||
|
||||
super.onResume();
|
||||
if (adapter != null) {
|
||||
adapter.clear();
|
||||
adapter.addAll(Content.getPurchasedItems());
|
||||
adapter.notifyDataSetChanged();
|
||||
} else {
|
||||
System.out.println("Adapter is null");
|
||||
}
|
||||
Log.d(LOG_TAG, "List Frag Resumed.");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import com.nokia.example.pepperfarm.iap.Payment;
|
||||
import com.nokia.example.pepperfarm.product.Config;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
import com.nokia.example.pepperfarm.product.Content.Product;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* This is the first screen that loads in the Pepper Farm application.
|
||||
* It shows you a list of Peppers you have already purchased and includes a button allowing you to purchase more Peppers.
|
||||
*/
|
||||
public class PepperFarmMainScreenActivity extends FragmentActivity implements MainScreenPepperListFragment.Callbacks {
|
||||
|
||||
/**
|
||||
* Used for logging so you know exactly where the logging messages are coming from.
|
||||
*/
|
||||
private final static String LOG_TAG = PepperFarmMainScreenActivity.class.getCanonicalName();
|
||||
|
||||
/**
|
||||
* A public string representing the full path name of this file. This is used in order to let the Enabler
|
||||
* know where to return to after a purchase request is completed.
|
||||
*/
|
||||
public final static String PEPPER_FARM_MAIN_SCREEN_ACTIVITY =
|
||||
"com.nokia.example.pepperfarm.client.PepperFarmMainScreenActivity";
|
||||
|
||||
|
||||
public static Payment purchaseHandler;
|
||||
|
||||
/**
|
||||
* Sets up the UI container for the Pepper Farm Main Screen
|
||||
* <p/>
|
||||
* As part of the set up, we use the Nokia In App Payment Library to request
|
||||
* the Enabler to return pricing data for each in app purchasable item we are selling.
|
||||
* For simplicity, this is done on the Main (UI) thread. Ideally you could spawn a new thread to set up
|
||||
* the NPayProductPricepoint objects and make the product data request to the library.
|
||||
*/
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.i(LOG_TAG, "Pepper Farm Main Screen Activity Created");
|
||||
Config.setVersiontitle(this);
|
||||
|
||||
setContentView(R.layout.pepper_farm_main_view);
|
||||
|
||||
Button buyPepperButton = (Button) findViewById(R.id.buy_button);
|
||||
buyPepperButton.setVisibility(View.INVISIBLE);
|
||||
|
||||
View product_list = findViewById(R.id.product_list);
|
||||
product_list.refreshDrawableState();
|
||||
|
||||
//Listener for the Purchase Requisition button
|
||||
buyPepperButton.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent("android.intent.action.PRODUCT_LIST");
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Button resetPurchases = (Button) findViewById(R.id.reset_purchases);
|
||||
resetPurchases.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
Log.i("resetPurchases", "Consuming all items");
|
||||
for (Product product : Content.ITEMS) {
|
||||
product.consumeItem();
|
||||
}
|
||||
if (MainScreenPepperListFragment.reference.adapter != null) {
|
||||
MainScreenPepperListFragment.reference.adapter.clear();
|
||||
MainScreenPepperListFragment.reference.adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Button fetchRestorables = (Button) findViewById(R.id.fetch_restorable_products);
|
||||
fetchRestorables.setOnClickListener
|
||||
(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
Log.i("fetchRestorables", "Fetching all restorable items");
|
||||
purchaseHandler.getPurchases(true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to allow a fragment to notify the controlling activity that a specific
|
||||
* item in the list has been selected. It could be used in layouts where you want to display the list
|
||||
* of items, and specific information about one item on the same screen, and need a way of displaying
|
||||
* to the user which item they have selected. Pepper Farm Simulator does not use this as each item
|
||||
* selection brings you to an entirely new activity.
|
||||
*/
|
||||
@Override
|
||||
public void onItemSelected(String id) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
Log.i(LOG_TAG, "onStart");
|
||||
super.onStart();
|
||||
try {
|
||||
if (purchaseHandler != null) {
|
||||
if (!purchaseHandler.npayAvailable) {
|
||||
purchaseHandler.connectToService(this);
|
||||
}
|
||||
} else {
|
||||
purchaseHandler = new Payment(this);
|
||||
purchaseHandler.connectToService(this);
|
||||
Log.i(LOG_TAG, "Npay initialization SUCCESS, waiting for service connection");
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
Log.e(LOG_TAG, "Npay initialization FAILED: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
Log.i(LOG_TAG, "onStop");
|
||||
super.onStop();
|
||||
purchaseHandler.cleanUp();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Window;
|
||||
import android.widget.ProgressBar;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
|
||||
/**
|
||||
* A splash screen used to give some time to complete the first get Product data call.
|
||||
* In a real game this may not be necessary as it is less likely (but still possible) that the user will get to any screens requiring
|
||||
* IAP Product data before the call returns.
|
||||
*/
|
||||
public class PepperFarmSplashScreen extends Activity {
|
||||
|
||||
private final int SECONDS_DELAYED = 1;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
//Show a little spinning wheel while we load.
|
||||
final ProgressDialog progressDialog = ProgressDialog.show(this, null, null);
|
||||
progressDialog.setContentView(new ProgressBar(this));
|
||||
|
||||
setContentView(R.layout.pepper_farm_splash_screen);
|
||||
|
||||
if (Content.products_initialized == false) {
|
||||
Content.initializeProducts(getResources());
|
||||
}
|
||||
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
startActivity(new Intent(PepperFarmSplashScreen.this, PepperFarmMainScreenActivity.class));
|
||||
progressDialog.dismiss();
|
||||
finish();
|
||||
}
|
||||
}, SECONDS_DELAYED * 1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
|
||||
public class Pepperfarm extends Application {
|
||||
|
||||
static Pepperfarm pepperfarm;
|
||||
|
||||
public Pepperfarm() {
|
||||
pepperfarm = this;
|
||||
}
|
||||
|
||||
public static Pepperfarm getContext() {
|
||||
return pepperfarm;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import com.nokia.example.pepperfarm.client.util.Purchase;
|
||||
import com.nokia.example.pepperfarm.iap.Payment;
|
||||
import com.nokia.example.pepperfarm.product.Config;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
import com.nokia.example.pepperfarm.product.Content.Product;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* An activity representing a list of purchasable IAP Products.
|
||||
* Much of the work of displaying the actual list is handled by ProductListFragment.java and especially ContentPurchaseAdapter,
|
||||
* which extends android.widget.ArrayAdapter
|
||||
* <p/>
|
||||
* This activity also implements the required
|
||||
* {@link ProductListFragment.Callbacks} interface to listen for item
|
||||
* selections.
|
||||
*/
|
||||
public class ProductListActivity extends FragmentActivity implements
|
||||
ProductListFragment.Callbacks {
|
||||
|
||||
public static Activity reference;
|
||||
public static Payment purchaseHandler;
|
||||
|
||||
/**
|
||||
* Used for logging so you know exactly where the logging messages are coming from.
|
||||
*/
|
||||
private final static String LOG_TAG = ProductListActivity.class.getCanonicalName();
|
||||
|
||||
|
||||
/**
|
||||
* Sets version title and enables the back button.
|
||||
*/
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.i(LOG_TAG, " onCreate");
|
||||
|
||||
Config.setVersiontitle(this);
|
||||
|
||||
setContentView(R.layout.activity_product_list);
|
||||
reference = this;
|
||||
|
||||
// Show the Up (Back) button in the action bar.
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback method from {@link ProductListFragment.Callbacks}
|
||||
*/
|
||||
@Override
|
||||
public void onItemSelected(String id) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is used to handle the Up (Back) button.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
switch (item.getItemId()) {
|
||||
|
||||
case android.R.id.home:
|
||||
// This ID represents the Home or Up button. In the case of this
|
||||
// activity, the Up button is shown. Use NavUtils to allow users
|
||||
// to navigate up one level in the application structure. For
|
||||
// more details, see the Navigation pattern on Android Design:
|
||||
//
|
||||
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
|
||||
//
|
||||
NavUtils.navigateUpTo(this, new Intent(this,
|
||||
MainScreenPepperListFragment.class));
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the purchase response.
|
||||
*/
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
|
||||
/*
|
||||
* Verify that onActivityResult was successful,
|
||||
*/
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
//Verify that the purchase was successful,
|
||||
int responseCode = data.getIntExtra("RESPONSE_CODE", Payment.RESULT_ERR);
|
||||
|
||||
try {
|
||||
|
||||
switch (responseCode) {
|
||||
|
||||
case Payment.RESULT_OK:
|
||||
//Unlock content
|
||||
if (data.getStringExtra("INAPP_PURCHASE_DATA") != null) {
|
||||
Purchase purchaseInfo = new Purchase(data.getStringExtra("INAPP_PURCHASE_DATA"));
|
||||
|
||||
purchaseHandler.setPurchaseInProgress(Payment.KEY_NOT_IN_PROGRESS);
|
||||
|
||||
Product purchasedProduct = Content.ITEM_MAP.get(purchaseInfo.getProductId());
|
||||
purchasedProduct.setPurchased(purchaseInfo);
|
||||
}
|
||||
|
||||
if (ProductListFragment.purchaseListAdapter != null) {
|
||||
ProductListFragment.purchaseListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
break;
|
||||
|
||||
case Payment.RESULT_ITEM_ALREADY_OWNED:
|
||||
Log.i(LOG_TAG, " User already bought the item");
|
||||
//Item has already been bought, but we still made it available for purchasing. Need to sync all purchases.
|
||||
purchaseHandler.getPurchases(true);
|
||||
break;
|
||||
|
||||
case Payment.RESULT_USER_CANCELED:
|
||||
//User pressed cancel in purchase dialog.
|
||||
Log.i(LOG_TAG, "User canceled purchase dialog");
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.i(LOG_TAG, "Purchase failed: " + responseCode);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.i(LOG_TAG, "Exception while parsing payment response: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void connectToService() {
|
||||
try {
|
||||
if (purchaseHandler != null) {
|
||||
if (!purchaseHandler.npayAvailable) {
|
||||
purchaseHandler.connectToService(this);
|
||||
}
|
||||
} else {
|
||||
purchaseHandler = new Payment(this);
|
||||
purchaseHandler.connectToService(this);
|
||||
Log.i(LOG_TAG, "Npay initialization SUCCESS, waiting for service connection");
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
Log.e(LOG_TAG, "Npay initialization FAILED: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
Log.i(LOG_TAG, "onStart");
|
||||
super.onStart();
|
||||
connectToService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.i(LOG_TAG, "onDestroy");
|
||||
super.onStop();
|
||||
purchaseHandler.cleanUp();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
import com.nokia.example.pepperfarm.product.adapters.ContentPurchaseAdapter;
|
||||
|
||||
/**
|
||||
* A list fragment representing a list of Products.
|
||||
* <p/>
|
||||
* Activities containing this fragment MUST implement the {@link Callbacks}
|
||||
* interface.
|
||||
*/
|
||||
public class ProductListFragment extends ListFragment {
|
||||
|
||||
|
||||
/**
|
||||
* The fragment's current callback object, which is notified of list item
|
||||
* clicks.
|
||||
*/
|
||||
private Callbacks mCallbacks = sDummyCallbacks;
|
||||
|
||||
/**
|
||||
* The ContentPurchaseAdapter extends android.widget.ArrayAdapter and is responsible for displaying a list of purchasable items.
|
||||
* If an item has already been purchased, it will appear greyed out.
|
||||
*/
|
||||
public static ContentPurchaseAdapter purchaseListAdapter = null;
|
||||
|
||||
/**
|
||||
* A callback interface that all activities containing this fragment must
|
||||
* implement. This mechanism allows activities to be notified of item
|
||||
* selections.
|
||||
*/
|
||||
public interface Callbacks {
|
||||
/**
|
||||
* Callback for when an item has been selected.
|
||||
*
|
||||
* @param id The id of the item selected
|
||||
*/
|
||||
public void onItemSelected(String id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A dummy implementation of the {@link Callbacks} interface that does
|
||||
* nothing. Used only when this fragment is not attached to an activity.
|
||||
*/
|
||||
private static Callbacks sDummyCallbacks = new Callbacks() {
|
||||
@Override
|
||||
public void onItemSelected(String id) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public ProductListFragment() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the List Adapter to ContentPurchaseAdapter.
|
||||
* <p/>
|
||||
* ContentPurchaseAdapter does the real work of setting the UI for each
|
||||
* Product in the list, through use of its getView method.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
purchaseListAdapter = new ContentPurchaseAdapter(getActivity(), R.layout.activity_product_list_row_view, Content.ITEMS);
|
||||
setListAdapter(purchaseListAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for error checking to make sure that any Activity attaching to this fragment properly supports
|
||||
* Callbacks.
|
||||
*/
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
// Activities containing this fragment must implement its callbacks.
|
||||
if (!(activity instanceof Callbacks)) {
|
||||
throw new IllegalStateException(
|
||||
"Activity must implement fragment's callbacks.");
|
||||
}
|
||||
|
||||
mCallbacks = (Callbacks) activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
|
||||
// Reset the active callbacks interface to the dummy implementation.
|
||||
mCallbacks = sDummyCallbacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the activity that an item has been selected.
|
||||
*/
|
||||
@Override
|
||||
public void onListItemClick(ListView listView, View view, int position,
|
||||
long id) {
|
||||
super.onListItemClick(listView, view, position, id);
|
||||
|
||||
// Notify the active callbacks interface (the activity, if the
|
||||
// fragment is attached to one) that an item has been selected.
|
||||
mCallbacks.onItemSelected(Content.ITEMS.get(position).productId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client.util;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents an in-app product's listing details.
|
||||
*/
|
||||
public class ProductDetails {
|
||||
String mProductId;
|
||||
String mType;
|
||||
String mPrice;
|
||||
String mCurrency;
|
||||
String mPriceFormatted;
|
||||
String mTitle;
|
||||
String mDescription;
|
||||
String mJson;
|
||||
String mPurchaseToken;
|
||||
boolean mRestorable;
|
||||
|
||||
public ProductDetails(String jsonProductDetails) throws JSONException {
|
||||
mJson = jsonProductDetails;
|
||||
JSONObject o = new JSONObject(mJson);
|
||||
|
||||
//optString returns empty string by default
|
||||
mProductId = o.optString("productId");
|
||||
mType = o.optString("type");
|
||||
mPrice = o.optString("priceValue");
|
||||
mCurrency = o.optString("currency");
|
||||
mPriceFormatted = o.optString("price");
|
||||
mTitle = o.optString("title");
|
||||
mDescription = o.optString("description");
|
||||
mPurchaseToken = o.optString("purchaseToken");
|
||||
mRestorable = false;
|
||||
if (o.optString("restorable").equalsIgnoreCase("true")) {
|
||||
mRestorable = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getProductId() {
|
||||
return mProductId;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
public String getPrice() {
|
||||
return mPrice;
|
||||
}
|
||||
|
||||
public String getCurrency() {
|
||||
return mCurrency;
|
||||
}
|
||||
|
||||
public String getPriceFormatted() {
|
||||
return mPriceFormatted;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public String getPurchaseToken() {
|
||||
return mPurchaseToken;
|
||||
}
|
||||
|
||||
public boolean getRestorable() {
|
||||
return mRestorable;
|
||||
}
|
||||
|
||||
|
||||
public void setRestore(boolean restore) {
|
||||
mRestorable = restore;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Product details:" + mJson;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.client.util;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents an in-app billing purchase.
|
||||
*/
|
||||
public class Purchase {
|
||||
String mProductId;
|
||||
String mDeveloperPayload;
|
||||
String mToken;
|
||||
String mOriginalJson;
|
||||
|
||||
public Purchase(String jsonPurchaseInfo) throws JSONException {
|
||||
if (jsonPurchaseInfo != null) {
|
||||
mOriginalJson = jsonPurchaseInfo;
|
||||
JSONObject o = new JSONObject(mOriginalJson);
|
||||
mProductId = o.optString("productId");
|
||||
mDeveloperPayload = o.optString("developerPayload");
|
||||
mToken = o.optString("purchaseToken");
|
||||
} else {
|
||||
mOriginalJson = "";
|
||||
mProductId = "";
|
||||
mDeveloperPayload = "";
|
||||
mToken = "";
|
||||
}
|
||||
}
|
||||
|
||||
public String getProductId() {
|
||||
return mProductId;
|
||||
}
|
||||
|
||||
public String getDeveloperPayload() {
|
||||
return mDeveloperPayload;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return mToken;
|
||||
}
|
||||
|
||||
public String getOriginalJson() {
|
||||
return mOriginalJson;
|
||||
}
|
||||
|
||||
public void setProductId(String input) {
|
||||
mProductId = input;
|
||||
}
|
||||
|
||||
public void setDeveloperPayload(String input) {
|
||||
mDeveloperPayload = input;
|
||||
}
|
||||
|
||||
public void setToken(String input) {
|
||||
mToken = input;
|
||||
}
|
||||
|
||||
public void setOriginalJson(String input) {
|
||||
mOriginalJson = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PurchaseInfo:" + mOriginalJson;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,449 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.iap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.*;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import com.nokia.example.pepperfarm.client.MainScreenPepperListFragment;
|
||||
import com.nokia.example.pepperfarm.client.ProductListFragment;
|
||||
import com.nokia.example.pepperfarm.client.util.ProductDetails;
|
||||
import com.nokia.example.pepperfarm.client.util.Purchase;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
import com.nokia.example.pepperfarm.product.Content.Product;
|
||||
import com.nokia.payment.iap.aidl.INokiaIAPService;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Payment implements ServiceConnection {
|
||||
|
||||
public Activity activity;
|
||||
public INokiaIAPService npay;
|
||||
public boolean npayAvailable = false;
|
||||
public static boolean purchases_asked = false;
|
||||
|
||||
public static final String SHARED_PREFERENCE_KEY = "IAPDATA";
|
||||
public static final String PRODUCT_ID_KEY = "PRODUCTKEY";
|
||||
public static final String KEY_NOT_IN_PROGRESS = "NOTINPROGRESS";
|
||||
public static final String PREFLOAD_FAILED = "FAIL";
|
||||
|
||||
|
||||
public static final int RESULT_OK = 0;// - success
|
||||
public static final int RESULT_USER_CANCELED = 1;// - user pressed back or canceled a dialog
|
||||
public static final int RESULT_BILLING_UNAVAILABLE = 3;// - this billing API version is not supported for the type requested or billing is otherwise impossible (for example there is no SIM card inserted)
|
||||
public static final int RESULT_ITEM_UNAVAILABLE = 4;// - requested ProductID is not available for purchase
|
||||
public static final int RESULT_DEVELOPER_ERROR = 5;// - invalid arguments provided to the API
|
||||
public static final int RESULT_ERROR = 6;// - Fatal error during the API action
|
||||
public static final int RESULT_ITEM_ALREADY_OWNED = 7;// - Failure to purchase since item is already owned
|
||||
public static final int RESULT_ITEM_NOT_OWNED = 8;// - Failure to consume since item is not owned
|
||||
public static final int RESULT_NO_SIM_CARD = 9;
|
||||
|
||||
public static final int RESULT_ERR = -100; //Used as a default value for Bundle.getInt, not part of the API
|
||||
|
||||
public static String PURCHASE_IN_PROGRESS_FOR_PRODUCT = "";
|
||||
|
||||
private static String ITEM_TYPE_INAPP = "inapp";
|
||||
|
||||
//This is the expected SHA1 finger-print in HEX format
|
||||
private static final String EXPECTED_SHA1_FINGERPRINT = "C476A7D71C4CB92641A699C1F1CAC93CA81E0396";
|
||||
|
||||
private static final String ENABLER_PACKAGENAME = "com.nokia.payment.iapenabler";
|
||||
|
||||
/**
|
||||
* Constructor of the Payment object. Needs to be initialized to access NIAP methods.
|
||||
*
|
||||
* @param context - The activity where Payment object is initialized
|
||||
*/
|
||||
public Payment(Context context) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Binds to Nokia in-app payment service.
|
||||
*
|
||||
* @param ctx
|
||||
* @throws GeneralSecurityException If Nokia In-App payment enabler fingerprint is not valid
|
||||
*/
|
||||
public void connectToService(Context ctx) throws GeneralSecurityException {
|
||||
|
||||
activity = (Activity) ctx;
|
||||
|
||||
//Verifies enabler fingerprint
|
||||
if (!verifyFingreprint()) {
|
||||
|
||||
npayAvailable = false;
|
||||
errorAlert("Nokia In-App Payment Enabler is not available.");
|
||||
|
||||
throw new GeneralSecurityException("Enabler fingerprint incorrect. Billing unavailable");
|
||||
|
||||
} else {
|
||||
//Enabler fingerprint OK. Continue with binding.
|
||||
Intent paymentEnabler = new Intent("com.nokia.payment.iapenabler.InAppBillingService.BIND");
|
||||
paymentEnabler.setPackage(ENABLER_PACKAGENAME);
|
||||
activity.bindService(paymentEnabler, this, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
|
||||
npay = INokiaIAPService.Stub.asInterface(service);
|
||||
|
||||
Log.i("onServiceConnected", "IAP service connected");
|
||||
npayAvailable = true;
|
||||
|
||||
if (isBillingAvailable()) {
|
||||
getPurchases(false);
|
||||
fetchPrices();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks SHA1 fingerprint of the enabler
|
||||
*
|
||||
* @return true if signature matches, false if package is not found or signature does not match.
|
||||
*/
|
||||
private boolean verifyFingreprint() {
|
||||
|
||||
try {
|
||||
PackageInfo info = activity.getBaseContext().getPackageManager().getPackageInfo(ENABLER_PACKAGENAME, PackageManager.GET_SIGNATURES);
|
||||
|
||||
if (info.signatures.length == 1) {
|
||||
|
||||
byte[] cert = info.signatures[0].toByteArray();
|
||||
MessageDigest digest;
|
||||
digest = MessageDigest.getInstance("SHA1");
|
||||
byte[] ENABLER_FINGERPRINT = digest.digest(cert);
|
||||
byte[] EXPECTED_FINGERPRINT = hexStringToByteArray(EXPECTED_SHA1_FINGERPRINT);
|
||||
|
||||
if (Arrays.equals(ENABLER_FINGERPRINT, EXPECTED_FINGERPRINT)) {
|
||||
Log.i("isBillingAvailable", "NIAP signature verified");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte[] hexStringToByteArray(String s) {
|
||||
int len = s.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public boolean isBillingAvailable() {
|
||||
|
||||
boolean isAvailable = false;
|
||||
|
||||
try {
|
||||
|
||||
int responseCode = RESULT_ERR;
|
||||
|
||||
if (npayAvailable)
|
||||
responseCode = npay.isBillingSupported(1, activity.getPackageName(), ITEM_TYPE_INAPP);
|
||||
|
||||
switch (responseCode) {
|
||||
case RESULT_OK:
|
||||
isAvailable = true;
|
||||
break;
|
||||
case RESULT_NO_SIM_CARD:
|
||||
errorAlert("No SIM. Please Insert SIM card.");
|
||||
break;
|
||||
case RESULT_ERR:
|
||||
errorAlert("Nokia In-App Payment Enabler is not available.");
|
||||
break;
|
||||
default:
|
||||
errorAlert("Billing is not supported. " + responseCode);
|
||||
break;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e("isBillingAvailable", e.getMessage(), e);
|
||||
errorAlert("Billing is not supported. " + e.getMessage());
|
||||
}
|
||||
return isAvailable;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the prices asynchronously
|
||||
*/
|
||||
public void fetchPrices() {
|
||||
|
||||
if (!isBillingAvailable())
|
||||
return;
|
||||
|
||||
for (Product p : Content.ITEMS) {
|
||||
if (p.getPrice() != "") {
|
||||
Log.i("fetchPrices", "Prices already available. Not fetching.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AsyncTask<Void, String, Void> pricesTask = new AsyncTask<Void, String, Void>() {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
|
||||
ArrayList<String> productIdArray = new ArrayList<String>(Content.ITEM_MAP.keySet());
|
||||
Bundle productBundle = new Bundle();
|
||||
productBundle.putStringArrayList("ITEM_ID_LIST", productIdArray);
|
||||
|
||||
try {
|
||||
Bundle priceInfo = npay.getProductDetails(1, activity.getPackageName(), ITEM_TYPE_INAPP, productBundle);
|
||||
|
||||
if (priceInfo.getInt("RESPONSE_CODE", RESULT_ERR) == RESULT_OK) {
|
||||
ArrayList<String> productDetailsList = priceInfo.getStringArrayList("DETAILS_LIST");
|
||||
|
||||
for (String productDetails : productDetailsList) {
|
||||
parseProductDetails(productDetails);
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.e("fetchPrices", "PRICE - priceInfo was not ok: Result was: " + priceInfo.getInt("RESPONSE_CODE", -100));
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
Log.e("fetchPrices", "PRODUCT DETAILS PARSING EXCEPTION: " + e.getMessage(), e);
|
||||
} catch (RemoteException e) {
|
||||
Log.e("fetchPrices", "PRICE EXCEPTION: " + e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void parseProductDetails(String productDetails) throws JSONException {
|
||||
|
||||
ProductDetails details = new ProductDetails(productDetails);
|
||||
|
||||
Log.i("fetchPrices", productDetails);
|
||||
|
||||
Product p = Content.ITEM_MAP.get(details.getProductId());
|
||||
|
||||
if (p != null) {
|
||||
p.setPrice(details.getPriceFormatted());
|
||||
Log.i("fetchPrices", "PRICE RECEIVED - " + details.getPrice() + " " + details.getCurrency());
|
||||
} else {
|
||||
Log.i("fetchPrices", "Unable to set price for product " + details.getProductId() + ". Product not found.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
if (ProductListFragment.purchaseListAdapter != null) {
|
||||
ProductListFragment.purchaseListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (MainScreenPepperListFragment.reference.adapter != null) {
|
||||
MainScreenPepperListFragment.reference.adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
pricesTask.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the products that we have already purchased
|
||||
*/
|
||||
public void getPurchases(boolean ignoreLifeCycleCheck) {
|
||||
|
||||
if (!isBillingAvailable())
|
||||
return;
|
||||
|
||||
|
||||
if (ignoreLifeCycleCheck == false) {
|
||||
if (purchases_asked) {
|
||||
Log.i("getPurchases", "Restorables already asked.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MainScreenPepperListFragment.getpeppers.setVisibility(View.INVISIBLE);
|
||||
MainScreenPepperListFragment.fetch_peppers_progressbar.setVisibility(View.VISIBLE);
|
||||
MainScreenPepperListFragment.fetching_peppers.setVisibility(View.VISIBLE);
|
||||
|
||||
AsyncTask<Void, String, Void> restoreTask = new AsyncTask<Void, String, Void>() {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
ArrayList<String> productIdArray = new ArrayList<String>(Content.ITEM_MAP.keySet());
|
||||
Bundle productBundle = new Bundle();
|
||||
productBundle.putStringArrayList("ITEM_ID_LIST", productIdArray);
|
||||
|
||||
try {
|
||||
Bundle purchases = npay.getPurchases(1, activity.getPackageName(), ITEM_TYPE_INAPP, productBundle, null);
|
||||
Log.i("getPurchases", "GET PURCHASES RESPONSE CODE: " + purchases.getInt("RESPONSE_CODE", RESULT_ERR));
|
||||
|
||||
if (purchases.getInt("RESPONSE_CODE", RESULT_ERR) == RESULT_OK) {
|
||||
|
||||
ArrayList<String> purchaseDataList = purchases.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
|
||||
|
||||
for (String purchaseData : purchaseDataList) {
|
||||
parsePurchaseData(purchaseData);
|
||||
}
|
||||
purchases_asked = true;
|
||||
} else {
|
||||
Log.e("getPurchases", "GET PURCHASES - response was not ok: Result was: " + purchases.getInt("RESPONSE_CODE", RESULT_ERR));
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
Log.e("getPurchases", "PURCHASE DATA PARSING EXCEPTION: " + e.getMessage(), e);
|
||||
} catch (RemoteException e) {
|
||||
Log.e("getPurchases", "EXCEPTION: " + e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void parsePurchaseData(String purchaseData) throws JSONException {
|
||||
|
||||
Purchase purchase = new Purchase(purchaseData);
|
||||
|
||||
Product p = Content.ITEM_MAP.get(purchase.getProductId());
|
||||
|
||||
if (p != null) {
|
||||
p.setPurchased(purchase);
|
||||
Log.i("getPurchases", "Restoring product " + purchase.getProductId() + " Purchase token: " + purchase.getToken());
|
||||
} else {
|
||||
Log.i("getPurchases", "Unable to restore product " + purchase.getProductId() + ". Product not found.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
MainScreenPepperListFragment.getpeppers.setVisibility(View.VISIBLE);
|
||||
MainScreenPepperListFragment.fetch_peppers_progressbar.setVisibility(View.GONE);
|
||||
MainScreenPepperListFragment.fetching_peppers.setVisibility(View.GONE);
|
||||
|
||||
if (ProductListFragment.purchaseListAdapter != null) {
|
||||
ProductListFragment.purchaseListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (MainScreenPepperListFragment.reference.adapter != null) {
|
||||
MainScreenPepperListFragment.reference.adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
restoreTask.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the payment process for the given product id. Application is suspended and the Npay service will complete the purchase.
|
||||
*
|
||||
* @param caller - The response from the purchase is sent to the caller activity. Caller activity must override "protected void onActivityResult(int requestCode, int resultCode, Intent data)" method to get the response.
|
||||
* @param product_id - The product id that is being purchased.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void startPayment(Activity caller, String product_id) throws Exception {
|
||||
|
||||
if (!isBillingAvailable())
|
||||
return;
|
||||
|
||||
Bundle intentBundle = npay.getBuyIntent(1, activity.getPackageName(), product_id, ITEM_TYPE_INAPP, "");
|
||||
PendingIntent purchaseIntent = intentBundle.getParcelable("BUY_INTENT");
|
||||
|
||||
//Set purchase in progress
|
||||
setPurchaseInProgress(product_id);
|
||||
|
||||
caller.startIntentSenderForResult(
|
||||
purchaseIntent.getIntentSender(),
|
||||
Integer.valueOf(0),
|
||||
new Intent(),
|
||||
Integer.valueOf(0),
|
||||
Integer.valueOf(0),
|
||||
Integer.valueOf(0));
|
||||
|
||||
}
|
||||
|
||||
public boolean consumeProduct(String productId, String token) {
|
||||
|
||||
if (!isBillingAvailable())
|
||||
return false;
|
||||
|
||||
boolean consumed = false;
|
||||
|
||||
try {
|
||||
Log.i("consumeProduct", "Consuming product: " + productId + " PurchaseToken: " + token);
|
||||
int response = npay.consumePurchase(1, activity.getPackageName(), productId, token);
|
||||
|
||||
if (response == RESULT_OK)
|
||||
consumed = true;
|
||||
|
||||
} catch (RemoteException e) {
|
||||
Log.e("isBillingAvailable", e.getMessage(), e);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
|
||||
public void setPurchaseInProgress(String productId) {
|
||||
if (productId.equals(KEY_NOT_IN_PROGRESS))
|
||||
Log.i("setPurchaseInProgress", "Resetting purcahse progress");
|
||||
else
|
||||
Log.i("setPurchaseInProgress", "Starting purchase for product " + productId);
|
||||
|
||||
SharedPreferences prefs = activity.getSharedPreferences(SHARED_PREFERENCE_KEY, Context.MODE_PRIVATE);
|
||||
prefs.edit().putString(PRODUCT_ID_KEY, productId).commit();
|
||||
}
|
||||
|
||||
public String getPurchaseInProgress() {
|
||||
SharedPreferences prefs = activity.getSharedPreferences(SHARED_PREFERENCE_KEY, Context.MODE_PRIVATE);
|
||||
String progress = prefs.getString(PRODUCT_ID_KEY, PREFLOAD_FAILED);
|
||||
Log.i("getPurchaseInProgress", "Purchase in progress is: " + progress);
|
||||
return progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an alert dialog when billing is not available.
|
||||
*/
|
||||
public void errorAlert(String msg) {
|
||||
Log.i("errorAlert", "Displaying error alert");
|
||||
new AlertDialog.Builder(activity).setTitle("PepperFarm").setMessage(msg).setNeutralButton("Close", null).show();
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
try {
|
||||
activity.unbindService(this);
|
||||
npayAvailable = false;
|
||||
Log.i("Payment", "Service disconnected");
|
||||
} catch (Exception ignored) {
|
||||
Log.i("cleanUp", "Service was cleared up already previously");
|
||||
//Unable to clean up. This means it is not registered or another error. Ignored exception
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.product;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
|
||||
public class Config {
|
||||
|
||||
public static final String APPTITLE = "Pepperfarm";
|
||||
public static final String PEPPER_FARM_PRODUCTID = "1081412";
|
||||
public static final String PEPPER_SEEDS_PRODUCTID = "1081413";
|
||||
public static final String JALAPENO_PRODUCTID = "1081414";
|
||||
public static final String SWEET_BELL_PRODUCTID = "1081416";
|
||||
public static final String HABENERO_PRODUCTID = "1081417";
|
||||
public static final String PEPPER_SPRAY_PRODUCTID = "1081418";
|
||||
|
||||
|
||||
/**
|
||||
* Sets the title of application according to APPTITLE
|
||||
*
|
||||
* @param reference
|
||||
*/
|
||||
public static void setVersiontitle(Activity reference) {
|
||||
try {
|
||||
PackageInfo pInfo = reference.getPackageManager().getPackageInfo(reference.getPackageName(), 0);
|
||||
String version_code = Integer.toString(pInfo.versionCode);
|
||||
|
||||
PackageInfo iapInfo = reference.getPackageManager().getPackageInfo("com.nokia.payment.iapenabler", 0);
|
||||
String iap_versioncode = Integer.toString(iapInfo.versionCode);
|
||||
String iap_version = iapInfo.versionName.concat(".").concat(iap_versioncode);
|
||||
|
||||
|
||||
reference.setTitle(APPTITLE.concat(" 1.0.").concat(version_code).concat(" / ").concat(iap_version));
|
||||
|
||||
} catch (NameNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,320 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.product;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import com.nokia.example.pepperfarm.client.R;
|
||||
import com.nokia.example.pepperfarm.client.util.Purchase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class used to represent a collection of Nokia Store IAP items.
|
||||
* If you wanted to further improve upon the idea of having an object representing in app purchasable content, you could consider
|
||||
* extending Inventory.java in order to not have to manually merge information between your own content objects and the ones
|
||||
* provided by Nokia IAP.
|
||||
*/
|
||||
public class Content {
|
||||
|
||||
public static boolean products_initialized = false;
|
||||
|
||||
/**
|
||||
* An array of items.
|
||||
*/
|
||||
public static List<Product> ITEMS = new ArrayList<Product>();
|
||||
|
||||
/**
|
||||
* A map of items, by ID.
|
||||
*/
|
||||
public static Map<String, Product> ITEM_MAP = new HashMap<String, Product>();
|
||||
|
||||
|
||||
public static void initializeProducts(Resources res) {
|
||||
//The first item is already paid for and non-consumable for the time being.
|
||||
Product pepper_farm = new Product(Config.PEPPER_FARM_PRODUCTID, res.getString(R.string.pepper_farm), res.getString(R.string.pepper_farm_description));
|
||||
pepper_farm.setProductType(Product.PRODUCT_TYPE.CONSUMABLE);
|
||||
|
||||
Product pepper_seeds = new Product(Config.PEPPER_SEEDS_PRODUCTID, res.getString(R.string.pepper_seeds), res.getString(R.string.pepper_seeds_description));
|
||||
Product jalapeno = new Product(Config.JALAPENO_PRODUCTID, res.getString(R.string.jalapeno), res.getString(R.string.jalapeno_description));
|
||||
Product sweet_bell = new Product(Config.SWEET_BELL_PRODUCTID, res.getString(R.string.sweet_bell), res.getString(R.string.sweet_bell_description));
|
||||
Product habenero = new Product(Config.HABENERO_PRODUCTID, res.getString(R.string.habenero), res.getString(R.string.habenero_description));
|
||||
Product pepper_spray = new Product(Config.PEPPER_SPRAY_PRODUCTID, res.getString(R.string.pepper_spray), res.getString(R.string.pepper_spray_description));
|
||||
|
||||
//Content.addItem(pepper_farm);
|
||||
Content.addItem(pepper_seeds);
|
||||
Content.addItem(jalapeno);
|
||||
Content.addItem(sweet_bell);
|
||||
Content.addItem(habenero);
|
||||
Content.addItem(pepper_spray);
|
||||
|
||||
products_initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a product to both the item map and item list.
|
||||
* We also check for duplicates.
|
||||
*
|
||||
* @param item
|
||||
*/
|
||||
public static void addItem(Product item) {
|
||||
if (ITEM_MAP.get(item.productId) == null) {
|
||||
ITEMS.add(item);
|
||||
ITEM_MAP.put(item.productId, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list containing all of the products where product.isPurchased() is true.
|
||||
*
|
||||
* @return A list of Products containing all purchased content.
|
||||
*/
|
||||
public static List<Product> getPurchasedItems() {
|
||||
|
||||
List<Product> purchasedItems = new ArrayList<Product>();
|
||||
for (Product product : ITEMS) {
|
||||
if (product.isPurchased()) {
|
||||
purchasedItems.add(product);
|
||||
}
|
||||
}
|
||||
|
||||
return purchasedItems;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An item representing a piece of content.
|
||||
*/
|
||||
public static class Product {
|
||||
|
||||
/**
|
||||
* The product type represents whether a Product is consumable or non-consumable.
|
||||
* A non-consumable product is bought once and kept permanently.
|
||||
* A consumable product can be consumed and then bought again. (Think coins or power ups)
|
||||
* The default is consumable.
|
||||
*/
|
||||
public static enum PRODUCT_TYPE {
|
||||
/**
|
||||
* A durable product is bought once and kept permanently.
|
||||
*/
|
||||
NON_CONSUMABLE,
|
||||
/**
|
||||
* A consumable product can be consumed and then re-purchased.
|
||||
*/
|
||||
CONSUMABLE
|
||||
}
|
||||
|
||||
/**
|
||||
* The product type. Either Consumable or Durable.
|
||||
*/
|
||||
public PRODUCT_TYPE productType;
|
||||
|
||||
/**
|
||||
* True if the item has already been purchased, false otherwise.
|
||||
*/
|
||||
public boolean purchased;
|
||||
|
||||
/**
|
||||
* @return The Product Type (DURABLE or CONSUMABLE)
|
||||
*/
|
||||
public PRODUCT_TYPE getProductType() {
|
||||
return productType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param productType The Product Type (DURABLE or CONSUMABLE)
|
||||
*/
|
||||
public void setProductType(PRODUCT_TYPE productType) {
|
||||
this.productType = productType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ID of the IAP product. Sometimes referred to as the resource ID.
|
||||
*/
|
||||
public String productId;
|
||||
|
||||
/**
|
||||
* The name of the product
|
||||
*/
|
||||
public String title;
|
||||
|
||||
public int count;
|
||||
|
||||
/**
|
||||
* @param id The product's ID.
|
||||
* @param title The name of the product
|
||||
* @param description The description of the product
|
||||
*/
|
||||
public Product(String id, String title, String description) {
|
||||
productId = id;
|
||||
this.title = title;
|
||||
purchased = false;
|
||||
productType = PRODUCT_TYPE.CONSUMABLE;
|
||||
this.description = description;
|
||||
price = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id The product's ID.
|
||||
* @param title The name of the product
|
||||
* @param description The description of the product
|
||||
* @param productType Enumeration whose value is either DURABLE or CONSUMANBLE.
|
||||
* @param parent The ID of the parent associated with this product.
|
||||
*/
|
||||
public Product(String id, String title, String description, PRODUCT_TYPE productType) {
|
||||
this(id, title, description);
|
||||
this.productType = productType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The product id
|
||||
*/
|
||||
public String getProductId() {
|
||||
return productId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param productId
|
||||
*/
|
||||
public void setProductId(String productId) {
|
||||
this.productId = productId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The product's title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param title
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The price of the product.
|
||||
*/
|
||||
public String getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param price The price of the product, without units. (No $)
|
||||
*/
|
||||
public void setPrice(String price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
/**
|
||||
* The description of the content.
|
||||
*/
|
||||
public String description;
|
||||
|
||||
/**
|
||||
* A string representing the price of the content.
|
||||
* Set by the Enabler after the first getProductData() request.
|
||||
*/
|
||||
public String price;
|
||||
|
||||
/**
|
||||
* A record of the item's purchase, assuming it has been purchased.
|
||||
* If the item has not been purchased, then this value will be null.
|
||||
*/
|
||||
private Purchase purchase = null;
|
||||
|
||||
/**
|
||||
* @return An object representing the items purchase, or null if the item was never purchased.
|
||||
*/
|
||||
public Purchase getPurchase() {
|
||||
return purchase;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the title of the Content
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the item has been purchased, false otherwise.
|
||||
*/
|
||||
public boolean isPurchased() {
|
||||
return purchased;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the content that the item has been purchased.
|
||||
*
|
||||
* @param thePurchase An object representing all the purchase details.
|
||||
*/
|
||||
public void setPurchased(Purchase thePurchase) {
|
||||
this.purchased = true;
|
||||
this.purchase = thePurchase;
|
||||
//count++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Consumes the purchase by setting purchased = false and nulling out the Purchase records.
|
||||
* If you call this on an item that was not purchased or was already consumed, the item will just be
|
||||
* marked as consumed without any error checking performed. (There is no real harm in doing this though.)
|
||||
*/
|
||||
public void consumeItem() {
|
||||
purchased = false;
|
||||
purchase = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the id of an image resource representing the full resolution available.
|
||||
*/
|
||||
public int getFullImage(Context ctx) {
|
||||
int imageResource = R.drawable.farm;
|
||||
|
||||
String title = getTitle();
|
||||
if (ctx.getString(R.string.sweet_bell).equals(title)) {
|
||||
imageResource = R.drawable.bellpepper;
|
||||
} else if (ctx.getString(R.string.pepper_spray).equals(title)) {
|
||||
imageResource = R.drawable.pepperspray;
|
||||
} else if (ctx.getString(R.string.pepper_farm).equals(title)) {
|
||||
imageResource = R.drawable.farm;
|
||||
} else if (ctx.getString(R.string.jalapeno).equals(title)) {
|
||||
imageResource = R.drawable.jalapeno;
|
||||
} else if (ctx.getString(R.string.habenero).equals(title)) {
|
||||
imageResource = R.drawable.habenero;
|
||||
} else if (ctx.getString(R.string.pepper_seeds).equals(title)) {
|
||||
imageResource = R.drawable.pepperseed;
|
||||
}
|
||||
return imageResource;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.product.adapters;
|
||||
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.*;
|
||||
import com.nokia.example.pepperfarm.client.MainScreenPepperListFragment;
|
||||
import com.nokia.example.pepperfarm.client.PepperFarmMainScreenActivity;
|
||||
import com.nokia.example.pepperfarm.client.ProductListFragment;
|
||||
import com.nokia.example.pepperfarm.client.R;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
import com.nokia.example.pepperfarm.product.Content.Product;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An adapter used to show a list of Peppers you currently own.
|
||||
* Used for the MainScreenPepeprListFragment and by association, PepperFarmMainScreenActivity.
|
||||
*/
|
||||
public class ContentListAdapter extends ArrayAdapter<Product> {
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used to take in a context, resource, and a List of products.
|
||||
*
|
||||
* @param context A context
|
||||
* @param resource The resource id of the caller
|
||||
* @param objects A list of products to be displayed
|
||||
*/
|
||||
public ContentListAdapter(Context context,
|
||||
int resource, List<Product> objects) {
|
||||
super(context, resource, objects);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* The context to use
|
||||
*/
|
||||
Context context;
|
||||
|
||||
|
||||
/**
|
||||
* For the Content List Adapter, all items are considered enabled.
|
||||
*
|
||||
* @param position
|
||||
* @return Always returns true
|
||||
*/
|
||||
public boolean isEnabled(int position) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true as all items are considered enabled in the list of peppers purchased.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public boolean areAllItemsEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the view representing a pepper that the user owns.
|
||||
* <p/>
|
||||
* The view will have:
|
||||
* 1. An image or placeholder image representing the pepper
|
||||
* 2. The name of the pepper
|
||||
* 3. A description of the pepper
|
||||
* 4. If the pepper is consumable, it will also have a button the user can press to consume it.
|
||||
*/
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
convertView = View.inflate(this.getContext(), R.layout.pepper_list_row_view, null);
|
||||
final Product currentProduct = Content.getPurchasedItems().get(position);
|
||||
|
||||
//Set the image
|
||||
ImageView image = (ImageView) convertView.findViewById(R.id.list_image);
|
||||
image.setImageResource(currentProduct.getFullImage(context));
|
||||
image.setVisibility(View.GONE);
|
||||
|
||||
//Set the name
|
||||
TextView text = (TextView) convertView.findViewById(R.id.pepperName);
|
||||
text.setText(currentProduct.getTitle());
|
||||
|
||||
//Set the description
|
||||
TextView description = (TextView) convertView.findViewById(R.id.pepper_description);
|
||||
description.setText(currentProduct.getDescription());
|
||||
description.setVisibility(View.GONE);
|
||||
|
||||
final Button consumeButton = (Button) convertView.findViewById(R.id.eat_pepper);
|
||||
|
||||
//Listener for the Purchase Requisition button
|
||||
consumeButton.setOnClickListener(
|
||||
new Button.OnClickListener() {
|
||||
public void onClick(final View v) {
|
||||
final String text = consumeButton.getText().toString();
|
||||
consumebuttonLoad(consumeButton);
|
||||
|
||||
AsyncTask<Void, String, Void> consumeTask = new AsyncTask<Void, String, Void>() {
|
||||
@Override
|
||||
protected void onProgressUpdate(String... values) {
|
||||
if (values[0] != null) {
|
||||
if (values[0].equals("0")) {
|
||||
notifyDataSetChanged();
|
||||
successAlert();
|
||||
} else {
|
||||
consumebuttonFail(consumeButton, text);
|
||||
if (MainScreenPepperListFragment.reference.adapter != null) {
|
||||
MainScreenPepperListFragment.reference.adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
boolean consumeOperation = PepperFarmMainScreenActivity.purchaseHandler.consumeProduct(currentProduct.getPurchase().getProductId(), currentProduct.getPurchase().getToken());
|
||||
System.out.println("Consume response: " + consumeOperation);
|
||||
if (consumeOperation) {
|
||||
Product consumedProduct = Content.ITEM_MAP.get(currentProduct.getPurchase().getProductId());
|
||||
consumedProduct.consumeItem();
|
||||
|
||||
String response[] = new String[1];
|
||||
response[0] = "0";
|
||||
this.publishProgress(response);
|
||||
return null;
|
||||
}
|
||||
|
||||
String response[] = new String[1];
|
||||
response[0] = "1";
|
||||
this.publishProgress(response);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
if (ProductListFragment.purchaseListAdapter != null) {
|
||||
ProductListFragment.purchaseListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
consumeTask.execute();
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
if (currentProduct.getProductType().equals(Product.PRODUCT_TYPE.NON_CONSUMABLE)) {
|
||||
//Non-consumable products should not have a consume button
|
||||
consumeButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
|
||||
return convertView;
|
||||
|
||||
}
|
||||
|
||||
public void successAlert() {
|
||||
new AlertDialog.Builder(context).setMessage("We hope you enjoyed your peppers.").setNeutralButton("Ok", null).show();
|
||||
}
|
||||
|
||||
public void consumebuttonFail(Button button, String text) {
|
||||
button.setText(text);
|
||||
button.setClickable(true);
|
||||
button.setEnabled(true);
|
||||
new AlertDialog.Builder(context).setTitle("Error").setMessage("Unable to consume item.").setNeutralButton("Close", null).show();
|
||||
}
|
||||
|
||||
public void consumebuttonLoad(Button button) {
|
||||
button.setText("Loading...");
|
||||
button.setClickable(false);
|
||||
button.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* No filter available for the ContentListAdapter, so this will always return null.
|
||||
*
|
||||
* @return Always returns null
|
||||
*/
|
||||
public Filter getFilter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of items in the list.
|
||||
*/
|
||||
@Override
|
||||
public int getCount() {
|
||||
return Content.getPurchasedItems().size();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* See the license text file delivered with this project for more information.
|
||||
*/
|
||||
|
||||
package com.nokia.example.pepperfarm.product.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import com.nokia.example.pepperfarm.client.ProductListActivity;
|
||||
import com.nokia.example.pepperfarm.client.R;
|
||||
import com.nokia.example.pepperfarm.product.Content;
|
||||
import com.nokia.example.pepperfarm.product.Content.Product;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The Content Purchase Adapter is used to display a list of Products that can be purchased.
|
||||
* If the item is already purchased, it will appear on the list but will be greyed out and unclickable.
|
||||
*/
|
||||
public class ContentPurchaseAdapter extends ArrayAdapter<Product> {
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used to set up the ContentPurchaseAdapter
|
||||
*
|
||||
* @param context The context
|
||||
* @param resource The resource
|
||||
* @param objects The list of Products the ContentPurchaseAdapter will display
|
||||
*/
|
||||
public ContentPurchaseAdapter(Context context,
|
||||
int resource, List<Product> objects) {
|
||||
super(context, resource, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specific content item is enabled. Otherwise returns false.
|
||||
*
|
||||
* @param position The position in the list of the item to check if enabled
|
||||
* @return True if the content item at the supplied position is enabled. False otherwise.
|
||||
*/
|
||||
public boolean isEnabled(int position) {
|
||||
if (Content.ITEMS.get(position).isPurchased()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets Android know that not all items in the list will always be enabled.
|
||||
*
|
||||
* @return Always returns false.
|
||||
*/
|
||||
public boolean areAllItemsEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does the primary work of setting up the UI for one specific item in the list.
|
||||
* An item will have:
|
||||
* 1. An image representing the item.
|
||||
* 2. A name, as determined by Product.getTitle()
|
||||
* 3. A price, which is assumed to have been previously queried through use of a
|
||||
* getProductData call to the Nokia In App Payment Library.
|
||||
* <p/>
|
||||
* If the item has already been purchased, the item will be greyed out and will not be clickable.
|
||||
*/
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
convertView = View.inflate(this.getContext(), R.layout.activity_product_list_row_view, null);
|
||||
|
||||
|
||||
final Product currentProduct = Content.ITEMS.get(position);
|
||||
|
||||
//Set the image
|
||||
ImageView image = (ImageView) convertView.findViewById(R.id.list_image);
|
||||
image.setVisibility(View.GONE);
|
||||
//image.setImageResource(currentProduct.getFullImage());
|
||||
|
||||
//Set the name
|
||||
TextView text = (TextView) convertView.findViewById(R.id.iapName);
|
||||
text.setText(currentProduct.getTitle());
|
||||
|
||||
//Set the price
|
||||
TextView price = (TextView) convertView.findViewById(R.id.price);
|
||||
price.setText(currentProduct.getPrice());
|
||||
|
||||
//Set the description
|
||||
TextView description = (TextView) convertView.findViewById(R.id.product_description);
|
||||
description.setText(currentProduct.getDescription());
|
||||
|
||||
Button buyPepperButton = (Button) convertView.findViewById(R.id.start_purchase);
|
||||
buyPepperButton.setOnClickListener
|
||||
(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
System.out.println("CLICK " + currentProduct.getProductId());
|
||||
try {
|
||||
ProductListActivity.purchaseHandler.startPayment(ProductListActivity.reference, currentProduct.getProductId());
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception while starting payment: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (currentProduct.isPurchased()) {
|
||||
buyPepperButton.setVisibility(View.INVISIBLE);
|
||||
price.setVisibility(View.INVISIBLE);
|
||||
/*
|
||||
* A purchased item:
|
||||
* 1. Will not have the arrow
|
||||
* 2. Will have a slightly different background color
|
||||
* 3. Will have greyed out text
|
||||
*/
|
||||
// text.setTextColor(Color.GRAY);
|
||||
// price.setTextColor(Color.GRAY);
|
||||
// convertView.setBackgroundColor(Color.parseColor("#EEEEEE"));
|
||||
}
|
||||
|
||||
return convertView;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
* Copyright (c) 2014 Nokia Corporation and/or its subsidiary(-ies).
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.nokia.payment.iap.aidl;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* All calls will give a response code with the following possible values<br/><br/>
|
||||
* RESULT_OK = 0 - success<br/>
|
||||
* RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog<br/>
|
||||
* RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested or billing is otherwise impossible<br/>
|
||||
* RESULT_ITEM_UNAVAILABLE = 4 - requested ProductID is not available for purchase<br/>
|
||||
* RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API<br/>
|
||||
* RESULT_ERROR = 6 - Fatal error during the API action<br/>
|
||||
* RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned<br/>
|
||||
* RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned<br/>
|
||||
* RESULT_NO_SIM = 9 - Billing is not available because there is no SIM card inserted<br/>
|
||||
*<br/>
|
||||
* Only supported itemtype, other values result in RESULT_DEVELOPER_ERROR<br/>
|
||||
* ITEM_TYPE_INAPP = "inapp";<br/>
|
||||
*/
|
||||
interface INokiaIAPService {
|
||||
/**
|
||||
* Checks support for the requested billing API version, package and in-app type.
|
||||
* @param apiVersion the billing version which the app is using
|
||||
* @param packageName the package name of the calling app
|
||||
@param type must always be "inapp"
|
||||
* @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 products<br/>
|
||||
* Given a list of Productids of a valid type in the productBundle, 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 Productids.
|
||||
* @param apiVersion billing API version that the Third-party is using
|
||||
* @param packageName the package name of the calling app
|
||||
* @param type must always be "inapp"
|
||||
* @param productBundle bundle containing a StringArrayList of Productids with key "ITEM_ID_LIST", when setProductMappings has been called this parameter can be null
|
||||
* @return Bundle containing the following key-value pairs<br/>
|
||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
||||
* failure as listed above.<br/>
|
||||
* "DETAILS_LIST" with a StringArrayList containing purchase information
|
||||
* in JSON format similar to:<br/>
|
||||
<br/>
|
||||
* '{ "productId" : "1264321", "isvalid", true, "title" : "Product title",<br/>
|
||||
* "shortdescription" : "Short description of the product", <br/>
|
||||
* "description" : "Longer description of the product", "priceValue" : "3.00",<br/>
|
||||
* "price" : "$3.00", "currency", "USD",<br/>
|
||||
* "purchaseToken" : "ZXlKMlpYSWlPaUl4TGpBaUxDSjBlRzVKWkNJNklrNVFRVmxmVkVWVFZGOVVXRTVmTVRFeE1TSXNJbkJ5YjJSSlpDSTZJakV3TWpNMk1qUWlmUT09",<br/>
|
||||
* "taxesincluded": true, "restorable" : true, "type" : "inapp" }'<br/><br/>
|
||||
* or if requested productId is not valid then<br/>
|
||||
* ''{ "productId" : "invalidproductid", "isvalid", false }'<br/>
|
||||
*/
|
||||
Bundle getProductDetails(int apiVersion, String packageName, String type, in Bundle productBundle);
|
||||
|
||||
/**
|
||||
* Returns a pending intent to launch the purchase flow for an in-app item by providing a ProductID,
|
||||
* 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 productId the ProductID of the in-app item as published in the developer console or as mapped through setProductMappings
|
||||
* @param type must always be "inapp"
|
||||
* @param developerPayload optional argument to be sent back with the purchase information
|
||||
* @return Bundle containing the following key-value pairs<br/><br/>
|
||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
||||
* failure as listed above.<br/>
|
||||
* "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.<br/><br/>
|
||||
* If the purchase is successful, the result data will contain the following key-value pairs<br/><br/>
|
||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
||||
* failure as listed above.<br/>
|
||||
* "INAPP_PURCHASE_DATA" - String in JSON format similar to<br/><br/>
|
||||
* '{"orderId":"X393XDAFFDAFAD",<br/>
|
||||
* "packageName":"com.your.app",<br/>
|
||||
* "productId":"1264321",<br/>
|
||||
* "purchaseToken" : "ZXlKMlpYSWlPaUl4TGpBaUxDSjBlRzVKWkNJNklrNVFRVmxmVkVWVFZGOVVXRTVmTVRFeE1TSXNJbkJ5YjJSSlpDSTZJakV3TWpNMk1qUWlmUT09",<br/>
|
||||
* "developerPayload":"" }'<br/><br/>
|
||||
* "INAPP_DATA_SIGNATURE" - currently empty string<br/>
|
||||
*/
|
||||
Bundle getBuyIntent(int apiVersion, String packageName, String productID, String type,
|
||||
String developerPayload);
|
||||
|
||||
/**
|
||||
* Returns the current products associated with current imei
|
||||
* @param apiVersion billing API version that the app is using
|
||||
* @param packageName package name of the calling app
|
||||
* @param type must always be "inapp"
|
||||
* @param productBundle bundle containing a StringArrayList of Productids with key "ITEM_ID_LIST", when setProductMappings has been called this parameter can be null
|
||||
* @param continuationToken - currently ignored
|
||||
* @return Bundle containing the following key-value pairs<br/>
|
||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
||||
* failure as listed above.<br/>
|
||||
* "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of owned products<br/>
|
||||
* "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing for each owned product json string
|
||||
* similar to following (please note that delveloperPayload field is currently empty):<br/><br/>
|
||||
* { "productId":"1264321",<br/>
|
||||
* "purchaseToken" : "ZXlKMlpYSWlPaUl4TGpBaUxDSjBlRzVKWkNJNklrNVFRVmxmVkVWVFZGOVVXRTVmTVRFeE1TSXNJbkJ5YjJSSlpDSTZJakV3TWpNMk1qUWlmUT09",<br/>
|
||||
* "developerPayload":"" }<br/>
|
||||
*/
|
||||
Bundle getPurchases(int apiVersion, String packageName, String type, in Bundle productBundle, String continuationToken );
|
||||
|
||||
/**
|
||||
* Consume the last purchase of the given product. 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 productId productId of purchase to be consumed, this argument can be empty or null
|
||||
* @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 productId, String purchaseToken);
|
||||
|
||||
/**
|
||||
* Set mapping between nokia productid-s and application internal productid-s
|
||||
* @param apiVersion billing API version that the app is using
|
||||
* @param packageName package name of the calling app
|
||||
* @param mappingsBundle - bundle containing mapping as key, value pairs where key is Nokia productid and value is calling applications internal id
|
||||
*/
|
||||
|
||||
int setProductMappings( int apiVersion, String packageName, in Bundle mappingsBundle );
|
||||
}
|
22
README.md
|
@ -1,4 +1,20 @@
|
|||
nokia-x-in-app-payment-samples
|
||||
==============================
|
||||
Nokia In-App Payment API samples for Nokia X
|
||||
============================================
|
||||
|
||||
Placeholder
|
||||
This project contains the simple examples demonstrating how to implement and
|
||||
port an application to utilise Nokia In-App Payment on Nokia X software
|
||||
platform.
|
||||
|
||||
What are the samples all about:
|
||||
|
||||
* **Payment One APK**: Demonstrates how to utilise both Nokia In-App Payment and
|
||||
Google In-App Billing in the same application. The resulting APK will run in
|
||||
both Nokia X and Google Android devices.
|
||||
* **Pepper Farm Simulator**: Demonstrates how to implement the support for
|
||||
Nokia In-App Payment enabler.
|
||||
|
||||
See the sample specific README and license files, located in the root folder of
|
||||
each sample, for more details.
|
||||
|
||||
Learn more about Nokia In-App Payment API in
|
||||
[Nokia X Developer's Library](http://developer.nokia.com/resources/library/nokia-x).
|
||||
|
|