| @@ -0,0 +1,109 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <JUCERPROJECT id="Z3D0EG" name="AnalyticsCollection" displaySplashScreen="0" | |||
| reportAppUsage="0" splashScreenColour="Dark" projectType="guiapp" | |||
| version="1.0.0" bundleIdentifier="com.yourcompany.AnalyticsCollection" | |||
| includeBinaryInAppConfig="1" cppLanguageStandard="11" companyCopyright="" | |||
| jucerVersion="5.1.2"> | |||
| <MAINGROUP id="aOi9Tf" name="AnalyticsCollection"> | |||
| <GROUP id="{527B2E17-B1B1-B919-CBEA-231058E23D74}" name="Source"> | |||
| <FILE id="qTLkDX" name="GoogleAnalyticsDestination.h" compile="0" resource="0" | |||
| file="Source/GoogleAnalyticsDestination.h"/> | |||
| <FILE id="DHs1bY" name="MainComponent.h" compile="0" resource="0" file="Source/MainComponent.h"/> | |||
| <FILE id="dsUiEq" name="Main.cpp" compile="1" resource="0" file="Source/Main.cpp"/> | |||
| </GROUP> | |||
| </MAINGROUP> | |||
| <EXPORTFORMATS> | |||
| <XCODE_MAC targetFolder="Builds/MacOSX"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="AnalyticsCollection" | |||
| enablePluginBinaryCopyStep="1"/> | |||
| <CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="AnalyticsCollection" | |||
| enablePluginBinaryCopyStep="1"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </XCODE_MAC> | |||
| <XCODE_IPHONE targetFolder="Builds/iOS" iosScreenOrientation="portraitlandscape" | |||
| iosDeviceFamily="1,2" iPadScreenOrientation="portraitlandscape"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="AnalyticsCollection" | |||
| enablePluginBinaryCopyStep="1"/> | |||
| <CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="AnalyticsCollection" | |||
| enablePluginBinaryCopyStep="1"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </XCODE_IPHONE> | |||
| <VS2017 targetFolder="Builds/VisualStudio2017"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="x64" | |||
| isDebug="1" optimisation="1" targetName="AnalyticsCollection" | |||
| debugInformationFormat="ProgramDatabase" enablePluginBinaryCopyStep="0"/> | |||
| <CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="x64" | |||
| isDebug="0" optimisation="3" targetName="AnalyticsCollection" | |||
| debugInformationFormat="None" enablePluginBinaryCopyStep="0" | |||
| linkTimeOptimisation="1"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </VS2017> | |||
| <LINUX_MAKE targetFolder="Builds/LinuxMakefile" extraDefs="JUCE_USE_CURL=1"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="AnalyticsCollection"/> | |||
| <CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="AnalyticsCollection"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </LINUX_MAKE> | |||
| <ANDROIDSTUDIO targetFolder="Builds/Android"> | |||
| <CONFIGURATIONS> | |||
| <CONFIGURATION name="Debug" androidArchitectures="armeabi x86" isDebug="1" optimisation="1" | |||
| targetName="AnalyticsCollection"/> | |||
| <CONFIGURATION name="Release" androidArchitectures="" isDebug="0" optimisation="3" | |||
| targetName="AnalyticsCollection"/> | |||
| </CONFIGURATIONS> | |||
| <MODULEPATHS> | |||
| <MODULEPATH id="juce_core" path="../../modules"/> | |||
| <MODULEPATH id="juce_events" path="../../modules"/> | |||
| <MODULEPATH id="juce_graphics" path="../../modules"/> | |||
| <MODULEPATH id="juce_data_structures" path="../../modules"/> | |||
| <MODULEPATH id="juce_gui_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </ANDROIDSTUDIO> | |||
| </EXPORTFORMATS> | |||
| <MODULES> | |||
| <MODULE id="juce_analytics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/> | |||
| <MODULE id="juce_core" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/> | |||
| <MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/> | |||
| <MODULE id="juce_events" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/> | |||
| <MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/> | |||
| <MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/> | |||
| </MODULES> | |||
| <JUCEOPTIONS/> | |||
| </JUCERPROJECT> | |||
| @@ -0,0 +1,89 @@ | |||
| apply plugin: 'com.android.application' | |||
| android { | |||
| compileSdkVersion 10 | |||
| buildToolsVersion "26.0.0" | |||
| externalNativeBuild { | |||
| cmake { | |||
| path "CMakeLists.txt" | |||
| } | |||
| } | |||
| signingConfigs { | |||
| juceSigning { | |||
| storeFile file("${System.properties['user.home']}${File.separator}.android${File.separator}debug.keystore") | |||
| storePassword "android" | |||
| keyAlias "androiddebugkey" | |||
| keyPassword "android" | |||
| storeType "jks" | |||
| } | |||
| } | |||
| defaultConfig { | |||
| applicationId "com.yourcompany.analyticscollection" | |||
| minSdkVersion 10 | |||
| targetSdkVersion 10 | |||
| externalNativeBuild { | |||
| cmake { | |||
| arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_PLATFORM=android-10", "-DANDROID_STL=c++_static", "-DANDROID_CPP_FEATURES=exceptions rtti", "-DANDROID_ARM_MODE=arm", "-DANDROID_ARM_NEON=TRUE" | |||
| cFlags "-fsigned-char" | |||
| cppFlags "-fsigned-char", "-std=c++11" | |||
| } | |||
| } | |||
| } | |||
| buildTypes { | |||
| debug { | |||
| initWith debug | |||
| debuggable true | |||
| jniDebuggable true | |||
| signingConfig signingConfigs.juceSigning | |||
| } | |||
| release { | |||
| initWith release | |||
| debuggable false | |||
| jniDebuggable false | |||
| signingConfig signingConfigs.juceSigning | |||
| } | |||
| } | |||
| productFlavors { | |||
| debug_ { | |||
| ndk { | |||
| abiFilters "armeabi", "x86" | |||
| } | |||
| externalNativeBuild { | |||
| cmake { | |||
| arguments "-DJUCE_BUILD_CONFIGFURATION=DEBUG", "-DCMAKE_CXX_FLAGS_DEBUG=-O0", "-DCMAKE_C_FLAGS_DEBUG=-O0" | |||
| } | |||
| } | |||
| } | |||
| release_ { | |||
| externalNativeBuild { | |||
| cmake { | |||
| arguments "-DJUCE_BUILD_CONFIGFURATION=RELEASE", "-DCMAKE_CXX_FLAGS_RELEASE=-O3", "-DCMAKE_C_FLAGS_RELEASE=-O3" | |||
| } | |||
| } | |||
| } | |||
| } | |||
| variantFilter { variant -> | |||
| def names = variant.flavors*.name | |||
| if (names.contains ("debug_") | |||
| && variant.buildType.name != "debug") { | |||
| setIgnore(true) | |||
| } | |||
| if (names.contains ("release_") | |||
| && variant.buildType.name != "release") { | |||
| setIgnore(true) | |||
| } | |||
| } | |||
| repositories { | |||
| } | |||
| dependencies { | |||
| } | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <resources> | |||
| <string name="app_name">AnalyticsCollection</string> | |||
| </resources> | |||
| @@ -0,0 +1,22 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.0" | |||
| package="com.yourcompany.analyticscollection"> | |||
| <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:anyDensity="true"/> | |||
| <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="10"/> | |||
| <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | |||
| <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | |||
| <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> | |||
| <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> | |||
| <uses-permission android:name="android.permission.BLUETOOTH"/> | |||
| <uses-permission android:name="android.permission.INTERNET"/> | |||
| <application android:label="@string/app_name"> | |||
| <activity android:name="AnalyticsCollection" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation" | |||
| android:screenOrientation="unspecified" android:launchMode="singleTask"> | |||
| <intent-filter> | |||
| <action android:name="android.intent.action.MAIN"/> | |||
| <category android:name="android.intent.category.LAUNCHER"/> | |||
| </intent-filter> | |||
| </activity> | |||
| </application> | |||
| </manifest> | |||
| @@ -0,0 +1,971 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| package com.android.vending.billing; | |||
| /** | |||
| * InAppBillingService is the service that provides in-app billing version 3 and beyond. | |||
| * This service provides the following features: | |||
| * 1. Provides a new API to get details of in-app items published for the app including | |||
| * price, type, title and description. | |||
| * 2. The purchase flow is synchronous and purchase information is available immediately | |||
| * after it completes. | |||
| * 3. Purchase information of in-app purchases is maintained within the Google Play system | |||
| * till the purchase is consumed. | |||
| * 4. An API to consume a purchase of an inapp item. All purchases of one-time | |||
| * in-app items are consumable and thereafter can be purchased again. | |||
| * 5. An API to get current purchases of the user immediately. This will not contain any | |||
| * consumed purchases. | |||
| * | |||
| * All calls will give a response code with the following possible values | |||
| * RESULT_OK = 0 - success | |||
| * RESULT_USER_CANCELED = 1 - User pressed back or canceled a dialog | |||
| * RESULT_SERVICE_UNAVAILABLE = 2 - The network connection is down | |||
| * RESULT_BILLING_UNAVAILABLE = 3 - This billing API version is not supported for the type requested | |||
| * RESULT_ITEM_UNAVAILABLE = 4 - Requested SKU is not available for purchase | |||
| * RESULT_DEVELOPER_ERROR = 5 - Invalid arguments provided to the API | |||
| * RESULT_ERROR = 6 - Fatal error during the API action | |||
| * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned | |||
| * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned | |||
| */ | |||
| public interface IInAppBillingService extends android.os.IInterface | |||
| { | |||
| /** Local-side IPC implementation stub class. */ | |||
| public static abstract class Stub extends android.os.Binder implements com.android.vending.billing.IInAppBillingService | |||
| { | |||
| private static final java.lang.String DESCRIPTOR = "com.android.vending.billing.IInAppBillingService"; | |||
| /** Construct the stub at attach it to the interface. */ | |||
| public Stub() | |||
| { | |||
| this.attachInterface(this, DESCRIPTOR); | |||
| } | |||
| /** | |||
| * Cast an IBinder object into an com.android.vending.billing.IInAppBillingService interface, | |||
| * generating a proxy if needed. | |||
| */ | |||
| public static com.android.vending.billing.IInAppBillingService asInterface(android.os.IBinder obj) | |||
| { | |||
| if ((obj==null)) { | |||
| return null; | |||
| } | |||
| android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); | |||
| if (((iin!=null)&&(iin instanceof com.android.vending.billing.IInAppBillingService))) { | |||
| return ((com.android.vending.billing.IInAppBillingService)iin); | |||
| } | |||
| return new com.android.vending.billing.IInAppBillingService.Stub.Proxy(obj); | |||
| } | |||
| @Override public android.os.IBinder asBinder() | |||
| { | |||
| return this; | |||
| } | |||
| @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException | |||
| { | |||
| switch (code) | |||
| { | |||
| case INTERFACE_TRANSACTION: | |||
| { | |||
| reply.writeString(DESCRIPTOR); | |||
| return true; | |||
| } | |||
| case TRANSACTION_isBillingSupported: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| int _result = this.isBillingSupported(_arg0, _arg1, _arg2); | |||
| reply.writeNoException(); | |||
| reply.writeInt(_result); | |||
| return true; | |||
| } | |||
| case TRANSACTION_getSkuDetails: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| android.os.Bundle _arg3; | |||
| if ((0!=data.readInt())) { | |||
| _arg3 = android.os.Bundle.CREATOR.createFromParcel(data); | |||
| } | |||
| else { | |||
| _arg3 = null; | |||
| } | |||
| android.os.Bundle _result = this.getSkuDetails(_arg0, _arg1, _arg2, _arg3); | |||
| reply.writeNoException(); | |||
| if ((_result!=null)) { | |||
| reply.writeInt(1); | |||
| _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); | |||
| } | |||
| else { | |||
| reply.writeInt(0); | |||
| } | |||
| return true; | |||
| } | |||
| case TRANSACTION_getBuyIntent: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| java.lang.String _arg3; | |||
| _arg3 = data.readString(); | |||
| java.lang.String _arg4; | |||
| _arg4 = data.readString(); | |||
| android.os.Bundle _result = this.getBuyIntent(_arg0, _arg1, _arg2, _arg3, _arg4); | |||
| reply.writeNoException(); | |||
| if ((_result!=null)) { | |||
| reply.writeInt(1); | |||
| _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); | |||
| } | |||
| else { | |||
| reply.writeInt(0); | |||
| } | |||
| return true; | |||
| } | |||
| case TRANSACTION_getPurchases: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| java.lang.String _arg3; | |||
| _arg3 = data.readString(); | |||
| android.os.Bundle _result = this.getPurchases(_arg0, _arg1, _arg2, _arg3); | |||
| reply.writeNoException(); | |||
| if ((_result!=null)) { | |||
| reply.writeInt(1); | |||
| _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); | |||
| } | |||
| else { | |||
| reply.writeInt(0); | |||
| } | |||
| return true; | |||
| } | |||
| case TRANSACTION_consumePurchase: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| int _result = this.consumePurchase(_arg0, _arg1, _arg2); | |||
| reply.writeNoException(); | |||
| reply.writeInt(_result); | |||
| return true; | |||
| } | |||
| case TRANSACTION_stub: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| int _result = this.stub(_arg0, _arg1, _arg2); | |||
| reply.writeNoException(); | |||
| reply.writeInt(_result); | |||
| return true; | |||
| } | |||
| case TRANSACTION_getBuyIntentToReplaceSkus: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.util.List<java.lang.String> _arg2; | |||
| _arg2 = data.createStringArrayList(); | |||
| java.lang.String _arg3; | |||
| _arg3 = data.readString(); | |||
| java.lang.String _arg4; | |||
| _arg4 = data.readString(); | |||
| java.lang.String _arg5; | |||
| _arg5 = data.readString(); | |||
| android.os.Bundle _result = this.getBuyIntentToReplaceSkus(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); | |||
| reply.writeNoException(); | |||
| if ((_result!=null)) { | |||
| reply.writeInt(1); | |||
| _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); | |||
| } | |||
| else { | |||
| reply.writeInt(0); | |||
| } | |||
| return true; | |||
| } | |||
| case TRANSACTION_getBuyIntentExtraParams: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| java.lang.String _arg3; | |||
| _arg3 = data.readString(); | |||
| java.lang.String _arg4; | |||
| _arg4 = data.readString(); | |||
| android.os.Bundle _arg5; | |||
| if ((0!=data.readInt())) { | |||
| _arg5 = android.os.Bundle.CREATOR.createFromParcel(data); | |||
| } | |||
| else { | |||
| _arg5 = null; | |||
| } | |||
| android.os.Bundle _result = this.getBuyIntentExtraParams(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); | |||
| reply.writeNoException(); | |||
| if ((_result!=null)) { | |||
| reply.writeInt(1); | |||
| _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); | |||
| } | |||
| else { | |||
| reply.writeInt(0); | |||
| } | |||
| return true; | |||
| } | |||
| case TRANSACTION_getPurchaseHistory: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| java.lang.String _arg3; | |||
| _arg3 = data.readString(); | |||
| android.os.Bundle _arg4; | |||
| if ((0!=data.readInt())) { | |||
| _arg4 = android.os.Bundle.CREATOR.createFromParcel(data); | |||
| } | |||
| else { | |||
| _arg4 = null; | |||
| } | |||
| android.os.Bundle _result = this.getPurchaseHistory(_arg0, _arg1, _arg2, _arg3, _arg4); | |||
| reply.writeNoException(); | |||
| if ((_result!=null)) { | |||
| reply.writeInt(1); | |||
| _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); | |||
| } | |||
| else { | |||
| reply.writeInt(0); | |||
| } | |||
| return true; | |||
| } | |||
| case TRANSACTION_isBillingSupportedExtraParams: | |||
| { | |||
| data.enforceInterface(DESCRIPTOR); | |||
| int _arg0; | |||
| _arg0 = data.readInt(); | |||
| java.lang.String _arg1; | |||
| _arg1 = data.readString(); | |||
| java.lang.String _arg2; | |||
| _arg2 = data.readString(); | |||
| android.os.Bundle _arg3; | |||
| if ((0!=data.readInt())) { | |||
| _arg3 = android.os.Bundle.CREATOR.createFromParcel(data); | |||
| } | |||
| else { | |||
| _arg3 = null; | |||
| } | |||
| int _result = this.isBillingSupportedExtraParams(_arg0, _arg1, _arg2, _arg3); | |||
| reply.writeNoException(); | |||
| reply.writeInt(_result); | |||
| return true; | |||
| } | |||
| } | |||
| return super.onTransact(code, data, reply, flags); | |||
| } | |||
| private static class Proxy implements com.android.vending.billing.IInAppBillingService | |||
| { | |||
| private android.os.IBinder mRemote; | |||
| Proxy(android.os.IBinder remote) | |||
| { | |||
| mRemote = remote; | |||
| } | |||
| @Override public android.os.IBinder asBinder() | |||
| { | |||
| return mRemote; | |||
| } | |||
| public java.lang.String getInterfaceDescriptor() | |||
| { | |||
| return DESCRIPTOR; | |||
| } | |||
| @Override public int isBillingSupported(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| int _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(type); | |||
| mRemote.transact(Stub.TRANSACTION_isBillingSupported, _data, _reply, 0); | |||
| _reply.readException(); | |||
| _result = _reply.readInt(); | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| /** | |||
| * Provides details of a list of SKUs | |||
| * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle | |||
| * with a list JSON strings containing the productId, price, title and description. | |||
| * This API can be called with a maximum of 20 SKUs. | |||
| * @param apiVersion billing API version that the app is using | |||
| * @param packageName the package name of the calling app | |||
| * @param type of the in-app items ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST" | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| * on failures. | |||
| * "DETAILS_LIST" with a StringArrayList containing purchase information | |||
| * in JSON format similar to: | |||
| * '{ "productId" : "exampleSku", | |||
| * "type" : "inapp", | |||
| * "price" : "$5.00", | |||
| * "price_currency": "USD", | |||
| * "price_amount_micros": 5000000, | |||
| * "title : "Example Title", | |||
| * "description" : "This is an example description" }' | |||
| */ | |||
| @Override public android.os.Bundle getSkuDetails(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle skusBundle) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| android.os.Bundle _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(type); | |||
| if ((skusBundle!=null)) { | |||
| _data.writeInt(1); | |||
| skusBundle.writeToParcel(_data, 0); | |||
| } | |||
| else { | |||
| _data.writeInt(0); | |||
| } | |||
| mRemote.transact(Stub.TRANSACTION_getSkuDetails, _data, _reply, 0); | |||
| _reply.readException(); | |||
| if ((0!=_reply.readInt())) { | |||
| _result = android.os.Bundle.CREATOR.createFromParcel(_reply); | |||
| } | |||
| else { | |||
| _result = null; | |||
| } | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| /** | |||
| * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU, | |||
| * the type, a unique purchase token and an optional developer payload. | |||
| * @param apiVersion billing API version that the app is using | |||
| * @param packageName package name of the calling app | |||
| * @param sku the SKU of the in-app item as published in the developer console | |||
| * @param type of the in-app item being purchased ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param developerPayload optional argument to be sent back with the purchase information | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| * on failures. | |||
| * "BUY_INTENT" - PendingIntent to start the purchase flow | |||
| * | |||
| * The Pending intent should be launched with startIntentSenderForResult. When purchase flow | |||
| * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. | |||
| * If the purchase is successful, the result data will contain the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response | |||
| * codes on failures. | |||
| * "INAPP_PURCHASE_DATA" - String in JSON format similar to | |||
| * '{"orderId":"12999763169054705758.1371079406387615", | |||
| * "packageName":"com.example.app", | |||
| * "productId":"exampleSku", | |||
| * "purchaseTime":1345678900000, | |||
| * "purchaseToken" : "122333444455555", | |||
| * "developerPayload":"example developer payload" }' | |||
| * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that | |||
| * was signed with the private key of the developer | |||
| */ | |||
| @Override public android.os.Bundle getBuyIntent(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| android.os.Bundle _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(sku); | |||
| _data.writeString(type); | |||
| _data.writeString(developerPayload); | |||
| mRemote.transact(Stub.TRANSACTION_getBuyIntent, _data, _reply, 0); | |||
| _reply.readException(); | |||
| if ((0!=_reply.readInt())) { | |||
| _result = android.os.Bundle.CREATOR.createFromParcel(_reply); | |||
| } | |||
| else { | |||
| _result = null; | |||
| } | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| /** | |||
| * Returns the current SKUs owned by the user of the type and package name specified along with | |||
| * purchase information and a signature of the data to be validated. | |||
| * This will return all SKUs that have been purchased in V3 and managed items purchased using | |||
| * V1 and V2 that have not been consumed. | |||
| * @param apiVersion billing API version that the app is using | |||
| * @param packageName package name of the calling app | |||
| * @param type of the in-app items being requested ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param continuationToken to be set as null for the first call, if the number of owned | |||
| * skus are too many, a continuationToken is returned in the response bundle. | |||
| * This method can be called again with the continuation token to get the next set of | |||
| * owned skus. | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| on failures. | |||
| * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs | |||
| * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information | |||
| * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures | |||
| * of the purchase information | |||
| * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the | |||
| * next set of in-app purchases. Only set if the | |||
| * user has more owned skus than the current list. | |||
| */ | |||
| @Override public android.os.Bundle getPurchases(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| android.os.Bundle _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(type); | |||
| _data.writeString(continuationToken); | |||
| mRemote.transact(Stub.TRANSACTION_getPurchases, _data, _reply, 0); | |||
| _reply.readException(); | |||
| if ((0!=_reply.readInt())) { | |||
| _result = android.os.Bundle.CREATOR.createFromParcel(_reply); | |||
| } | |||
| else { | |||
| _result = null; | |||
| } | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| @Override public int consumePurchase(int apiVersion, java.lang.String packageName, java.lang.String purchaseToken) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| int _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(purchaseToken); | |||
| mRemote.transact(Stub.TRANSACTION_consumePurchase, _data, _reply, 0); | |||
| _reply.readException(); | |||
| _result = _reply.readInt(); | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| @Override public int stub(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| int _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(type); | |||
| mRemote.transact(Stub.TRANSACTION_stub, _data, _reply, 0); | |||
| _reply.readException(); | |||
| _result = _reply.readInt(); | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| /** | |||
| * Returns a pending intent to launch the purchase flow for upgrading or downgrading a | |||
| * subscription. The existing owned SKU(s) should be provided along with the new SKU that | |||
| * the user is upgrading or downgrading to. | |||
| * @param apiVersion billing API version that the app is using, must be 5 or later | |||
| * @param packageName package name of the calling app | |||
| * @param oldSkus the SKU(s) that the user is upgrading or downgrading from, | |||
| * if null or empty this method will behave like {@link #getBuyIntent} | |||
| * @param newSku the SKU that the user is upgrading or downgrading to | |||
| * @param type of the item being purchased, currently must be "subs" | |||
| * @param developerPayload optional argument to be sent back with the purchase information | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| * on failures. | |||
| * "BUY_INTENT" - PendingIntent to start the purchase flow | |||
| * | |||
| * The Pending intent should be launched with startIntentSenderForResult. When purchase flow | |||
| * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. | |||
| * If the purchase is successful, the result data will contain the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response | |||
| * codes on failures. | |||
| * "INAPP_PURCHASE_DATA" - String in JSON format similar to | |||
| * '{"orderId":"12999763169054705758.1371079406387615", | |||
| * "packageName":"com.example.app", | |||
| * "productId":"exampleSku", | |||
| * "purchaseTime":1345678900000, | |||
| * "purchaseToken" : "122333444455555", | |||
| * "developerPayload":"example developer payload" }' | |||
| * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that | |||
| * was signed with the private key of the developer | |||
| */ | |||
| @Override public android.os.Bundle getBuyIntentToReplaceSkus(int apiVersion, java.lang.String packageName, java.util.List<java.lang.String> oldSkus, java.lang.String newSku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| android.os.Bundle _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeStringList(oldSkus); | |||
| _data.writeString(newSku); | |||
| _data.writeString(type); | |||
| _data.writeString(developerPayload); | |||
| mRemote.transact(Stub.TRANSACTION_getBuyIntentToReplaceSkus, _data, _reply, 0); | |||
| _reply.readException(); | |||
| if ((0!=_reply.readInt())) { | |||
| _result = android.os.Bundle.CREATOR.createFromParcel(_reply); | |||
| } | |||
| else { | |||
| _result = null; | |||
| } | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| /** | |||
| * Returns a pending intent to launch the purchase flow for an in-app item. This method is | |||
| * a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams} | |||
| * parameter. This parameter is a Bundle of optional keys and values that affect the | |||
| * operation of the method. | |||
| * @param apiVersion billing API version that the app is using, must be 6 or later | |||
| * @param packageName package name of the calling app | |||
| * @param sku the SKU of the in-app item as published in the developer console | |||
| * @param type of the in-app item being purchased ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param developerPayload optional argument to be sent back with the purchase information | |||
| * @extraParams a Bundle with the following optional keys: | |||
| * "skusToReplace" - List<String> - an optional list of SKUs that the user is | |||
| * upgrading or downgrading from. | |||
| * Pass this field if the purchase is upgrading or downgrading | |||
| * existing subscriptions. | |||
| * The specified SKUs are replaced with the SKUs that the user is | |||
| * purchasing. Google Play replaces the specified SKUs at the start of | |||
| * the next billing cycle. | |||
| * "replaceSkusProration" - Boolean - whether the user should be credited for any unused | |||
| * subscription time on the SKUs they are upgrading or downgrading. | |||
| * If you set this field to true, Google Play swaps out the old SKUs | |||
| * and credits the user with the unused value of their subscription | |||
| * time on a pro-rated basis. | |||
| * Google Play applies this credit to the new subscription, and does | |||
| * not begin billing the user for the new subscription until after | |||
| * the credit is used up. | |||
| * If you set this field to false, the user does not receive credit for | |||
| * any unused subscription time and the recurrence date does not | |||
| * change. | |||
| * Default value is true. Ignored if you do not pass skusToReplace. | |||
| * "accountId" - String - an optional obfuscated string that is uniquely | |||
| * associated with the user's account in your app. | |||
| * If you pass this value, Google Play can use it to detect irregular | |||
| * activity, such as many devices making purchases on the same | |||
| * account in a short period of time. | |||
| * Do not use the developer ID or the user's Google ID for this field. | |||
| * In addition, this field should not contain the user's ID in | |||
| * cleartext. | |||
| * We recommend that you use a one-way hash to generate a string from | |||
| * the user's ID, and store the hashed string in this field. | |||
| * "vr" - Boolean - an optional flag indicating whether the returned intent | |||
| * should start a VR purchase flow. The apiVersion must also be 7 or | |||
| * later to use this flag. | |||
| */ | |||
| @Override public android.os.Bundle getBuyIntentExtraParams(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload, android.os.Bundle extraParams) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| android.os.Bundle _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(sku); | |||
| _data.writeString(type); | |||
| _data.writeString(developerPayload); | |||
| if ((extraParams!=null)) { | |||
| _data.writeInt(1); | |||
| extraParams.writeToParcel(_data, 0); | |||
| } | |||
| else { | |||
| _data.writeInt(0); | |||
| } | |||
| mRemote.transact(Stub.TRANSACTION_getBuyIntentExtraParams, _data, _reply, 0); | |||
| _reply.readException(); | |||
| if ((0!=_reply.readInt())) { | |||
| _result = android.os.Bundle.CREATOR.createFromParcel(_reply); | |||
| } | |||
| else { | |||
| _result = null; | |||
| } | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| /** | |||
| * Returns the most recent purchase made by the user for each SKU, even if that purchase is | |||
| * expired, canceled, or consumed. | |||
| * @param apiVersion billing API version that the app is using, must be 6 or later | |||
| * @param packageName package name of the calling app | |||
| * @param type of the in-app items being requested ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param continuationToken to be set as null for the first call, if the number of owned | |||
| * skus is too large, a continuationToken is returned in the response bundle. | |||
| * This method can be called again with the continuation token to get the next set of | |||
| * owned skus. | |||
| * @param extraParams a Bundle with extra params that would be appended into http request | |||
| * query string. Not used at this moment. Reserved for future functionality. | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value: RESULT_OK(0) if success, | |||
| * {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures. | |||
| * | |||
| * "INAPP_PURCHASE_ITEM_LIST" - ArrayList<String> containing the list of SKUs | |||
| * "INAPP_PURCHASE_DATA_LIST" - ArrayList<String> containing the purchase information | |||
| * "INAPP_DATA_SIGNATURE_LIST"- ArrayList<String> containing the signatures | |||
| * of the purchase information | |||
| * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the | |||
| * next set of in-app purchases. Only set if the | |||
| * user has more owned skus than the current list. | |||
| */ | |||
| @Override public android.os.Bundle getPurchaseHistory(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken, android.os.Bundle extraParams) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| android.os.Bundle _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(type); | |||
| _data.writeString(continuationToken); | |||
| if ((extraParams!=null)) { | |||
| _data.writeInt(1); | |||
| extraParams.writeToParcel(_data, 0); | |||
| } | |||
| else { | |||
| _data.writeInt(0); | |||
| } | |||
| mRemote.transact(Stub.TRANSACTION_getPurchaseHistory, _data, _reply, 0); | |||
| _reply.readException(); | |||
| if ((0!=_reply.readInt())) { | |||
| _result = android.os.Bundle.CREATOR.createFromParcel(_reply); | |||
| } | |||
| else { | |||
| _result = null; | |||
| } | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| @Override public int isBillingSupportedExtraParams(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle extraParams) throws android.os.RemoteException | |||
| { | |||
| android.os.Parcel _data = android.os.Parcel.obtain(); | |||
| android.os.Parcel _reply = android.os.Parcel.obtain(); | |||
| int _result; | |||
| try { | |||
| _data.writeInterfaceToken(DESCRIPTOR); | |||
| _data.writeInt(apiVersion); | |||
| _data.writeString(packageName); | |||
| _data.writeString(type); | |||
| if ((extraParams!=null)) { | |||
| _data.writeInt(1); | |||
| extraParams.writeToParcel(_data, 0); | |||
| } | |||
| else { | |||
| _data.writeInt(0); | |||
| } | |||
| mRemote.transact(Stub.TRANSACTION_isBillingSupportedExtraParams, _data, _reply, 0); | |||
| _reply.readException(); | |||
| _result = _reply.readInt(); | |||
| } | |||
| finally { | |||
| _reply.recycle(); | |||
| _data.recycle(); | |||
| } | |||
| return _result; | |||
| } | |||
| } | |||
| static final int TRANSACTION_isBillingSupported = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); | |||
| static final int TRANSACTION_getSkuDetails = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); | |||
| static final int TRANSACTION_getBuyIntent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); | |||
| static final int TRANSACTION_getPurchases = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); | |||
| static final int TRANSACTION_consumePurchase = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); | |||
| static final int TRANSACTION_stub = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); | |||
| static final int TRANSACTION_getBuyIntentToReplaceSkus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); | |||
| static final int TRANSACTION_getBuyIntentExtraParams = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); | |||
| static final int TRANSACTION_getPurchaseHistory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); | |||
| static final int TRANSACTION_isBillingSupportedExtraParams = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9); | |||
| } | |||
| public int isBillingSupported(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException; | |||
| /** | |||
| * Provides details of a list of SKUs | |||
| * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle | |||
| * with a list JSON strings containing the productId, price, title and description. | |||
| * This API can be called with a maximum of 20 SKUs. | |||
| * @param apiVersion billing API version that the app is using | |||
| * @param packageName the package name of the calling app | |||
| * @param type of the in-app items ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST" | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| * on failures. | |||
| * "DETAILS_LIST" with a StringArrayList containing purchase information | |||
| * in JSON format similar to: | |||
| * '{ "productId" : "exampleSku", | |||
| * "type" : "inapp", | |||
| * "price" : "$5.00", | |||
| * "price_currency": "USD", | |||
| * "price_amount_micros": 5000000, | |||
| * "title : "Example Title", | |||
| * "description" : "This is an example description" }' | |||
| */ | |||
| public android.os.Bundle getSkuDetails(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle skusBundle) throws android.os.RemoteException; | |||
| /** | |||
| * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU, | |||
| * the type, a unique purchase token and an optional developer payload. | |||
| * @param apiVersion billing API version that the app is using | |||
| * @param packageName package name of the calling app | |||
| * @param sku the SKU of the in-app item as published in the developer console | |||
| * @param type of the in-app item being purchased ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param developerPayload optional argument to be sent back with the purchase information | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| * on failures. | |||
| * "BUY_INTENT" - PendingIntent to start the purchase flow | |||
| * | |||
| * The Pending intent should be launched with startIntentSenderForResult. When purchase flow | |||
| * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. | |||
| * If the purchase is successful, the result data will contain the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response | |||
| * codes on failures. | |||
| * "INAPP_PURCHASE_DATA" - String in JSON format similar to | |||
| * '{"orderId":"12999763169054705758.1371079406387615", | |||
| * "packageName":"com.example.app", | |||
| * "productId":"exampleSku", | |||
| * "purchaseTime":1345678900000, | |||
| * "purchaseToken" : "122333444455555", | |||
| * "developerPayload":"example developer payload" }' | |||
| * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that | |||
| * was signed with the private key of the developer | |||
| */ | |||
| public android.os.Bundle getBuyIntent(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException; | |||
| /** | |||
| * Returns the current SKUs owned by the user of the type and package name specified along with | |||
| * purchase information and a signature of the data to be validated. | |||
| * This will return all SKUs that have been purchased in V3 and managed items purchased using | |||
| * V1 and V2 that have not been consumed. | |||
| * @param apiVersion billing API version that the app is using | |||
| * @param packageName package name of the calling app | |||
| * @param type of the in-app items being requested ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param continuationToken to be set as null for the first call, if the number of owned | |||
| * skus are too many, a continuationToken is returned in the response bundle. | |||
| * This method can be called again with the continuation token to get the next set of | |||
| * owned skus. | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| on failures. | |||
| * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs | |||
| * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information | |||
| * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures | |||
| * of the purchase information | |||
| * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the | |||
| * next set of in-app purchases. Only set if the | |||
| * user has more owned skus than the current list. | |||
| */ | |||
| public android.os.Bundle getPurchases(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken) throws android.os.RemoteException; | |||
| public int consumePurchase(int apiVersion, java.lang.String packageName, java.lang.String purchaseToken) throws android.os.RemoteException; | |||
| public int stub(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException; | |||
| /** | |||
| * Returns a pending intent to launch the purchase flow for upgrading or downgrading a | |||
| * subscription. The existing owned SKU(s) should be provided along with the new SKU that | |||
| * the user is upgrading or downgrading to. | |||
| * @param apiVersion billing API version that the app is using, must be 5 or later | |||
| * @param packageName package name of the calling app | |||
| * @param oldSkus the SKU(s) that the user is upgrading or downgrading from, | |||
| * if null or empty this method will behave like {@link #getBuyIntent} | |||
| * @param newSku the SKU that the user is upgrading or downgrading to | |||
| * @param type of the item being purchased, currently must be "subs" | |||
| * @param developerPayload optional argument to be sent back with the purchase information | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes | |||
| * on failures. | |||
| * "BUY_INTENT" - PendingIntent to start the purchase flow | |||
| * | |||
| * The Pending intent should be launched with startIntentSenderForResult. When purchase flow | |||
| * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. | |||
| * If the purchase is successful, the result data will contain the following key-value pairs | |||
| * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response | |||
| * codes on failures. | |||
| * "INAPP_PURCHASE_DATA" - String in JSON format similar to | |||
| * '{"orderId":"12999763169054705758.1371079406387615", | |||
| * "packageName":"com.example.app", | |||
| * "productId":"exampleSku", | |||
| * "purchaseTime":1345678900000, | |||
| * "purchaseToken" : "122333444455555", | |||
| * "developerPayload":"example developer payload" }' | |||
| * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that | |||
| * was signed with the private key of the developer | |||
| */ | |||
| public android.os.Bundle getBuyIntentToReplaceSkus(int apiVersion, java.lang.String packageName, java.util.List<java.lang.String> oldSkus, java.lang.String newSku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException; | |||
| /** | |||
| * Returns a pending intent to launch the purchase flow for an in-app item. This method is | |||
| * a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams} | |||
| * parameter. This parameter is a Bundle of optional keys and values that affect the | |||
| * operation of the method. | |||
| * @param apiVersion billing API version that the app is using, must be 6 or later | |||
| * @param packageName package name of the calling app | |||
| * @param sku the SKU of the in-app item as published in the developer console | |||
| * @param type of the in-app item being purchased ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param developerPayload optional argument to be sent back with the purchase information | |||
| * @extraParams a Bundle with the following optional keys: | |||
| * "skusToReplace" - List<String> - an optional list of SKUs that the user is | |||
| * upgrading or downgrading from. | |||
| * Pass this field if the purchase is upgrading or downgrading | |||
| * existing subscriptions. | |||
| * The specified SKUs are replaced with the SKUs that the user is | |||
| * purchasing. Google Play replaces the specified SKUs at the start of | |||
| * the next billing cycle. | |||
| * "replaceSkusProration" - Boolean - whether the user should be credited for any unused | |||
| * subscription time on the SKUs they are upgrading or downgrading. | |||
| * If you set this field to true, Google Play swaps out the old SKUs | |||
| * and credits the user with the unused value of their subscription | |||
| * time on a pro-rated basis. | |||
| * Google Play applies this credit to the new subscription, and does | |||
| * not begin billing the user for the new subscription until after | |||
| * the credit is used up. | |||
| * If you set this field to false, the user does not receive credit for | |||
| * any unused subscription time and the recurrence date does not | |||
| * change. | |||
| * Default value is true. Ignored if you do not pass skusToReplace. | |||
| * "accountId" - String - an optional obfuscated string that is uniquely | |||
| * associated with the user's account in your app. | |||
| * If you pass this value, Google Play can use it to detect irregular | |||
| * activity, such as many devices making purchases on the same | |||
| * account in a short period of time. | |||
| * Do not use the developer ID or the user's Google ID for this field. | |||
| * In addition, this field should not contain the user's ID in | |||
| * cleartext. | |||
| * We recommend that you use a one-way hash to generate a string from | |||
| * the user's ID, and store the hashed string in this field. | |||
| * "vr" - Boolean - an optional flag indicating whether the returned intent | |||
| * should start a VR purchase flow. The apiVersion must also be 7 or | |||
| * later to use this flag. | |||
| */ | |||
| public android.os.Bundle getBuyIntentExtraParams(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload, android.os.Bundle extraParams) throws android.os.RemoteException; | |||
| /** | |||
| * Returns the most recent purchase made by the user for each SKU, even if that purchase is | |||
| * expired, canceled, or consumed. | |||
| * @param apiVersion billing API version that the app is using, must be 6 or later | |||
| * @param packageName package name of the calling app | |||
| * @param type of the in-app items being requested ("inapp" for one-time purchases | |||
| * and "subs" for subscriptions) | |||
| * @param continuationToken to be set as null for the first call, if the number of owned | |||
| * skus is too large, a continuationToken is returned in the response bundle. | |||
| * This method can be called again with the continuation token to get the next set of | |||
| * owned skus. | |||
| * @param extraParams a Bundle with extra params that would be appended into http request | |||
| * query string. Not used at this moment. Reserved for future functionality. | |||
| * @return Bundle containing the following key-value pairs | |||
| * "RESPONSE_CODE" with int value: RESULT_OK(0) if success, | |||
| * {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures. | |||
| * | |||
| * "INAPP_PURCHASE_ITEM_LIST" - ArrayList<String> containing the list of SKUs | |||
| * "INAPP_PURCHASE_DATA_LIST" - ArrayList<String> containing the purchase information | |||
| * "INAPP_DATA_SIGNATURE_LIST"- ArrayList<String> containing the signatures | |||
| * of the purchase information | |||
| * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the | |||
| * next set of in-app purchases. Only set if the | |||
| * user has more owned skus than the current list. | |||
| */ | |||
| public android.os.Bundle getPurchaseHistory(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken, android.os.Bundle extraParams) throws android.os.RemoteException; | |||
| public int isBillingSupportedExtraParams(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle extraParams) throws android.os.RemoteException; | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <resources> | |||
| <string name="app_name">AnalyticsCollection</string> | |||
| </resources> | |||
| @@ -0,0 +1,14 @@ | |||
| buildscript { | |||
| repositories { | |||
| jcenter() | |||
| } | |||
| dependencies { | |||
| classpath 'com.android.tools.build:gradle:2.3.3' | |||
| } | |||
| } | |||
| allprojects { | |||
| repositories { | |||
| jcenter() | |||
| } | |||
| } | |||
| @@ -0,0 +1,202 @@ | |||
| Apache License | |||
| Version 2.0, January 2004 | |||
| http://www.apache.org/licenses/ | |||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
| 1. Definitions. | |||
| "License" shall mean the terms and conditions for use, reproduction, | |||
| and distribution as defined by Sections 1 through 9 of this document. | |||
| "Licensor" shall mean the copyright owner or entity authorized by | |||
| the copyright owner that is granting the License. | |||
| "Legal Entity" shall mean the union of the acting entity and all | |||
| other entities that control, are controlled by, or are under common | |||
| control with that entity. For the purposes of this definition, | |||
| "control" means (i) the power, direct or indirect, to cause the | |||
| direction or management of such entity, whether by contract or | |||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
| outstanding shares, or (iii) beneficial ownership of such entity. | |||
| "You" (or "Your") shall mean an individual or Legal Entity | |||
| exercising permissions granted by this License. | |||
| "Source" form shall mean the preferred form for making modifications, | |||
| including but not limited to software source code, documentation | |||
| source, and configuration files. | |||
| "Object" form shall mean any form resulting from mechanical | |||
| transformation or translation of a Source form, including but | |||
| not limited to compiled object code, generated documentation, | |||
| and conversions to other media types. | |||
| "Work" shall mean the work of authorship, whether in Source or | |||
| Object form, made available under the License, as indicated by a | |||
| copyright notice that is included in or attached to the work | |||
| (an example is provided in the Appendix below). | |||
| "Derivative Works" shall mean any work, whether in Source or Object | |||
| form, that is based on (or derived from) the Work and for which the | |||
| editorial revisions, annotations, elaborations, or other modifications | |||
| represent, as a whole, an original work of authorship. For the purposes | |||
| of this License, Derivative Works shall not include works that remain | |||
| separable from, or merely link (or bind by name) to the interfaces of, | |||
| the Work and Derivative Works thereof. | |||
| "Contribution" shall mean any work of authorship, including | |||
| the original version of the Work and any modifications or additions | |||
| to that Work or Derivative Works thereof, that is intentionally | |||
| submitted to Licensor for inclusion in the Work by the copyright owner | |||
| or by an individual or Legal Entity authorized to submit on behalf of | |||
| the copyright owner. For the purposes of this definition, "submitted" | |||
| means any form of electronic, verbal, or written communication sent | |||
| to the Licensor or its representatives, including but not limited to | |||
| communication on electronic mailing lists, source code control systems, | |||
| and issue tracking systems that are managed by, or on behalf of, the | |||
| Licensor for the purpose of discussing and improving the Work, but | |||
| excluding communication that is conspicuously marked or otherwise | |||
| designated in writing by the copyright owner as "Not a Contribution." | |||
| "Contributor" shall mean Licensor and any individual or Legal Entity | |||
| on behalf of whom a Contribution has been received by Licensor and | |||
| subsequently incorporated within the Work. | |||
| 2. Grant of Copyright License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| copyright license to reproduce, prepare Derivative Works of, | |||
| publicly display, publicly perform, sublicense, and distribute the | |||
| Work and such Derivative Works in Source or Object form. | |||
| 3. Grant of Patent License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| (except as stated in this section) patent license to make, have made, | |||
| use, offer to sell, sell, import, and otherwise transfer the Work, | |||
| where such license applies only to those patent claims licensable | |||
| by such Contributor that are necessarily infringed by their | |||
| Contribution(s) alone or by combination of their Contribution(s) | |||
| with the Work to which such Contribution(s) was submitted. If You | |||
| institute patent litigation against any entity (including a | |||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
| or a Contribution incorporated within the Work constitutes direct | |||
| or contributory patent infringement, then any patent licenses | |||
| granted to You under this License for that Work shall terminate | |||
| as of the date such litigation is filed. | |||
| 4. Redistribution. You may reproduce and distribute copies of the | |||
| Work or Derivative Works thereof in any medium, with or without | |||
| modifications, and in Source or Object form, provided that You | |||
| meet the following conditions: | |||
| (a) You must give any other recipients of the Work or | |||
| Derivative Works a copy of this License; and | |||
| (b) You must cause any modified files to carry prominent notices | |||
| stating that You changed the files; and | |||
| (c) You must retain, in the Source form of any Derivative Works | |||
| that You distribute, all copyright, patent, trademark, and | |||
| attribution notices from the Source form of the Work, | |||
| excluding those notices that do not pertain to any part of | |||
| the Derivative Works; and | |||
| (d) If the Work includes a "NOTICE" text file as part of its | |||
| distribution, then any Derivative Works that You distribute must | |||
| include a readable copy of the attribution notices contained | |||
| within such NOTICE file, excluding those notices that do not | |||
| pertain to any part of the Derivative Works, in at least one | |||
| of the following places: within a NOTICE text file distributed | |||
| as part of the Derivative Works; within the Source form or | |||
| documentation, if provided along with the Derivative Works; or, | |||
| within a display generated by the Derivative Works, if and | |||
| wherever such third-party notices normally appear. The contents | |||
| of the NOTICE file are for informational purposes only and | |||
| do not modify the License. You may add Your own attribution | |||
| notices within Derivative Works that You distribute, alongside | |||
| or as an addendum to the NOTICE text from the Work, provided | |||
| that such additional attribution notices cannot be construed | |||
| as modifying the License. | |||
| You may add Your own copyright statement to Your modifications and | |||
| may provide additional or different license terms and conditions | |||
| for use, reproduction, or distribution of Your modifications, or | |||
| for any such Derivative Works as a whole, provided Your use, | |||
| reproduction, and distribution of the Work otherwise complies with | |||
| the conditions stated in this License. | |||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | |||
| any Contribution intentionally submitted for inclusion in the Work | |||
| by You to the Licensor shall be under the terms and conditions of | |||
| this License, without any additional terms or conditions. | |||
| Notwithstanding the above, nothing herein shall supersede or modify | |||
| the terms of any separate license agreement you may have executed | |||
| with Licensor regarding such Contributions. | |||
| 6. Trademarks. This License does not grant permission to use the trade | |||
| names, trademarks, service marks, or product names of the Licensor, | |||
| except as required for reasonable and customary use in describing the | |||
| origin of the Work and reproducing the content of the NOTICE file. | |||
| 7. Disclaimer of Warranty. Unless required by applicable law or | |||
| agreed to in writing, Licensor provides the Work (and each | |||
| Contributor provides its Contributions) on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
| implied, including, without limitation, any warranties or conditions | |||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
| PARTICULAR PURPOSE. You are solely responsible for determining the | |||
| appropriateness of using or redistributing the Work and assume any | |||
| risks associated with Your exercise of permissions under this License. | |||
| 8. Limitation of Liability. In no event and under no legal theory, | |||
| whether in tort (including negligence), contract, or otherwise, | |||
| unless required by applicable law (such as deliberate and grossly | |||
| negligent acts) or agreed to in writing, shall any Contributor be | |||
| liable to You for damages, including any direct, indirect, special, | |||
| incidental, or consequential damages of any character arising as a | |||
| result of this License or out of the use or inability to use the | |||
| Work (including but not limited to damages for loss of goodwill, | |||
| work stoppage, computer failure or malfunction, or any and all | |||
| other commercial damages or losses), even if such Contributor | |||
| has been advised of the possibility of such damages. | |||
| 9. Accepting Warranty or Additional Liability. While redistributing | |||
| the Work or Derivative Works thereof, You may choose to offer, | |||
| and charge a fee for, acceptance of support, warranty, indemnity, | |||
| or other liability obligations and/or rights consistent with this | |||
| License. However, in accepting such obligations, You may act only | |||
| on Your own behalf and on Your sole responsibility, not on behalf | |||
| of any other Contributor, and only if You agree to indemnify, | |||
| defend, and hold each Contributor harmless for any liability | |||
| incurred by, or claims asserted against, such Contributor by reason | |||
| of your accepting any such warranty or additional liability. | |||
| END OF TERMS AND CONDITIONS | |||
| APPENDIX: How to apply the Apache License to your work. | |||
| To apply the Apache License to your work, attach the following | |||
| boilerplate notice, with the fields enclosed by brackets "{}" | |||
| replaced with your own identifying information. (Don't include | |||
| the brackets!) The text should be enclosed in the appropriate | |||
| comment syntax for the file format. We also recommend that a | |||
| file or class name and description of purpose be included on the | |||
| same "printed page" as the copyright notice for easier | |||
| identification within third-party archives. | |||
| Copyright {yyyy} {name of copyright owner} | |||
| 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. | |||
| @@ -0,0 +1 @@ | |||
| distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip | |||
| @@ -0,0 +1,160 @@ | |||
| #!/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 | |||
| # 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\"`/" >/dev/null | |||
| APP_HOME="`pwd -P`" | |||
| cd "$SAVED" >/dev/null | |||
| 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"` | |||
| JAVACMD=`cygpath --unix "$JAVACMD"` | |||
| # 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 | |||
| @@ -0,0 +1 @@ | |||
| include ':app' | |||
| @@ -0,0 +1,135 @@ | |||
| # Automatically generated makefile, created by the Projucer | |||
| # Don't edit this file! Your changes will be overwritten when you re-save the Projucer project! | |||
| # build with "V=1" for verbose builds | |||
| ifeq ($(V), 1) | |||
| V_AT = | |||
| else | |||
| V_AT = @ | |||
| endif | |||
| # (this disables dependency generation if multiple architectures are set) | |||
| DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD) | |||
| ifndef STRIP | |||
| STRIP=strip | |||
| endif | |||
| ifndef AR | |||
| AR=ar | |||
| endif | |||
| ifndef CONFIG | |||
| CONFIG=Debug | |||
| endif | |||
| ifeq ($(CONFIG),Debug) | |||
| JUCE_BINDIR := build | |||
| JUCE_LIBDIR := build | |||
| JUCE_OBJDIR := build/intermediate/Debug | |||
| JUCE_OUTDIR := build | |||
| ifeq ($(TARGET_ARCH),) | |||
| TARGET_ARCH := -march=native | |||
| endif | |||
| JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DDEBUG=1 -D_DEBUG=1 -DJUCE_USE_CURL=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=1.0.0 -DJUCE_APP_VERSION_HEX=0x10000 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) | |||
| JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 | |||
| JUCE_TARGET_APP := AnalyticsCollection | |||
| JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 $(CFLAGS) | |||
| JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++11 $(CXXFLAGS) | |||
| JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell pkg-config --libs freetype2 libcurl x11 xext xinerama) -ldl -lpthread -lrt $(LDFLAGS) | |||
| CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) | |||
| endif | |||
| ifeq ($(CONFIG),Release) | |||
| JUCE_BINDIR := build | |||
| JUCE_LIBDIR := build | |||
| JUCE_OBJDIR := build/intermediate/Release | |||
| JUCE_OUTDIR := build | |||
| ifeq ($(TARGET_ARCH),) | |||
| TARGET_ARCH := -march=native | |||
| endif | |||
| JUCE_CPPFLAGS := $(DEPFLAGS) -DLINUX=1 -DNDEBUG=1 -DJUCE_USE_CURL=1 -DJUCER_LINUX_MAKE_6D53C8B4=1 -DJUCE_APP_VERSION=1.0.0 -DJUCE_APP_VERSION_HEX=0x10000 $(shell pkg-config --cflags freetype2 libcurl x11 xext xinerama) -pthread -I../../JuceLibraryCode -I../../../../modules $(CPPFLAGS) | |||
| JUCE_CPPFLAGS_APP := -DJucePlugin_Build_VST=0 -DJucePlugin_Build_VST3=0 -DJucePlugin_Build_AU=0 -DJucePlugin_Build_AUv3=0 -DJucePlugin_Build_RTAS=0 -DJucePlugin_Build_AAX=0 -DJucePlugin_Build_Standalone=0 | |||
| JUCE_TARGET_APP := AnalyticsCollection | |||
| JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -O3 $(CFLAGS) | |||
| JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++11 $(CXXFLAGS) | |||
| JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) $(shell pkg-config --libs freetype2 libcurl x11 xext xinerama) -fvisibility=hidden -ldl -lpthread -lrt $(LDFLAGS) | |||
| CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR) | |||
| endif | |||
| OBJECTS_APP := \ | |||
| $(JUCE_OBJDIR)/Main_90ebc5c2.o \ | |||
| $(JUCE_OBJDIR)/include_juce_analytics_f8e9fa94.o \ | |||
| $(JUCE_OBJDIR)/include_juce_core_f26d17db.o \ | |||
| $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o \ | |||
| $(JUCE_OBJDIR)/include_juce_events_fd7d695.o \ | |||
| $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o \ | |||
| $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o \ | |||
| .PHONY: clean all | |||
| all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) | |||
| $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : check-pkg-config $(OBJECTS_APP) $(RESOURCES) | |||
| @echo Linking "AnalyticsCollection - App" | |||
| -$(V_AT)mkdir -p $(JUCE_BINDIR) | |||
| -$(V_AT)mkdir -p $(JUCE_LIBDIR) | |||
| -$(V_AT)mkdir -p $(JUCE_OUTDIR) | |||
| $(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(RESOURCES) $(TARGET_ARCH) | |||
| $(JUCE_OBJDIR)/Main_90ebc5c2.o: ../../Source/Main.cpp | |||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||
| @echo "Compiling Main.cpp" | |||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||
| $(JUCE_OBJDIR)/include_juce_analytics_f8e9fa94.o: ../../JuceLibraryCode/include_juce_analytics.cpp | |||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||
| @echo "Compiling include_juce_analytics.cpp" | |||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||
| $(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp | |||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||
| @echo "Compiling include_juce_core.cpp" | |||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||
| $(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp | |||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||
| @echo "Compiling include_juce_data_structures.cpp" | |||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||
| $(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp | |||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||
| @echo "Compiling include_juce_events.cpp" | |||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||
| $(JUCE_OBJDIR)/include_juce_graphics_f817e147.o: ../../JuceLibraryCode/include_juce_graphics.cpp | |||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||
| @echo "Compiling include_juce_graphics.cpp" | |||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||
| $(JUCE_OBJDIR)/include_juce_gui_basics_e3f79785.o: ../../JuceLibraryCode/include_juce_gui_basics.cpp | |||
| -$(V_AT)mkdir -p $(JUCE_OBJDIR) | |||
| @echo "Compiling include_juce_gui_basics.cpp" | |||
| $(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<" | |||
| check-pkg-config: | |||
| @command -v pkg-config >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; } | |||
| @pkg-config --print-errors freetype2 libcurl x11 xext xinerama | |||
| clean: | |||
| @echo Cleaning AnalyticsCollection | |||
| $(V_AT)$(CLEANCMD) | |||
| strip: | |||
| @echo Stripping AnalyticsCollection | |||
| -$(V_AT)$(STRIP) --strip-unneeded $(JUCE_OUTDIR)/$(TARGET) | |||
| -include $(OBJECTS_APP:%.o=%.d) | |||
| @@ -0,0 +1,251 @@ | |||
| // !$*UTF8*$! | |||
| { | |||
| archiveVersion = 1; | |||
| classes = { | |||
| }; | |||
| objectVersion = 46; | |||
| objects = { | |||
| 95AA57DF380DDDCD099D4000 = {isa = PBXBuildFile; fileRef = 707149C59A1AF9752E428B97; }; | |||
| B45E888BC48139CA81112E4A = {isa = PBXBuildFile; fileRef = 570EA8E9B2BD490DAA35F86E; }; | |||
| 375013DDDA026F2709E4FDAD = {isa = PBXBuildFile; fileRef = C858CF44E96D416E4B6B9266; }; | |||
| 877F68400FB5A15B39719C61 = {isa = PBXBuildFile; fileRef = 08EEB00E1779867598046EB6; }; | |||
| 38EE4929FFB8B83FB37B6E73 = {isa = PBXBuildFile; fileRef = FBCE051A0BA6C9FA3E64B47B; }; | |||
| A0DA914E3E16F49D60A5A47F = {isa = PBXBuildFile; fileRef = 3D44D3C7CC1020729BBF62BB; }; | |||
| D293FC19C031441D146F2410 = {isa = PBXBuildFile; fileRef = 6A86C9751E9DCFA62D4562DB; }; | |||
| 962036B1BB2EDB0F9D53E125 = {isa = PBXBuildFile; fileRef = 33B9806EFA95DA05ACD9344E; }; | |||
| 6297B7A712B1E5A74311F162 = {isa = PBXBuildFile; fileRef = 5DC0FF6BC4AE24FABC41F20E; }; | |||
| 132F9FBC9EB36AF2E755325D = {isa = PBXBuildFile; fileRef = AD2CFF58DA5E1C6EDF9CC399; }; | |||
| 805CDCC5840B0D713C286826 = {isa = PBXBuildFile; fileRef = A0DDFB3559C431E96EC59392; }; | |||
| C09B5A3CD0643CF37C9CF851 = {isa = PBXBuildFile; fileRef = 61FADB63565026F559F43F3B; }; | |||
| A1DF340E80EC501B1DBE75A0 = {isa = PBXBuildFile; fileRef = 65311EED96DCA9B62EBFEA04; }; | |||
| 02589D465A73E0112B97BD3A = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_core"; path = "../../../../modules/juce_core"; sourceTree = "SOURCE_ROOT"; }; | |||
| 08EEB00E1779867598046EB6 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; | |||
| 1AA9DA887BE127DCED5228BB = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_events"; path = "../../../../modules/juce_events"; sourceTree = "SOURCE_ROOT"; }; | |||
| 33B9806EFA95DA05ACD9344E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_juce_analytics.cpp"; path = "../../JuceLibraryCode/include_juce_analytics.cpp"; sourceTree = "SOURCE_ROOT"; }; | |||
| 3D44D3C7CC1020729BBF62BB = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; }; | |||
| 5219A3D3BECB8C7135C90377 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_basics"; path = "../../../../modules/juce_gui_basics"; sourceTree = "SOURCE_ROOT"; }; | |||
| 570EA8E9B2BD490DAA35F86E = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; | |||
| 5DC0FF6BC4AE24FABC41F20E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_core.mm"; path = "../../JuceLibraryCode/include_juce_core.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| 61FADB63565026F559F43F3B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_graphics.mm"; path = "../../JuceLibraryCode/include_juce_graphics.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| 65311EED96DCA9B62EBFEA04 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_gui_basics.mm"; path = "../../JuceLibraryCode/include_juce_gui_basics.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| 6A86C9751E9DCFA62D4562DB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Main.cpp; path = ../../Source/Main.cpp; sourceTree = "SOURCE_ROOT"; }; | |||
| 707149C59A1AF9752E428B97 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnalyticsCollection.app; sourceTree = "BUILT_PRODUCTS_DIR"; }; | |||
| 7A9FA859A2C2AE9FDDC99AD9 = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-App.plist"; path = "Info-App.plist"; sourceTree = "SOURCE_ROOT"; }; | |||
| 886AEA380A40C905503764EB = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_graphics"; path = "../../../../modules/juce_graphics"; sourceTree = "SOURCE_ROOT"; }; | |||
| 8A74F3F7422C89A897D93397 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppConfig.h; path = ../../JuceLibraryCode/AppConfig.h; sourceTree = "SOURCE_ROOT"; }; | |||
| 8B927F72BA8726A064560942 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoogleAnalyticsDestination.h; path = ../../Source/GoogleAnalyticsDestination.h; sourceTree = "SOURCE_ROOT"; }; | |||
| 91208A06115D573563996967 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = "SOURCE_ROOT"; }; | |||
| 996BEF5ADCE2EC85EB9F637F = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_data_structures"; path = "../../../../modules/juce_data_structures"; sourceTree = "SOURCE_ROOT"; }; | |||
| A0DDFB3559C431E96EC59392 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_events.mm"; path = "../../JuceLibraryCode/include_juce_events.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| AD2CFF58DA5E1C6EDF9CC399 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_data_structures.mm"; path = "../../JuceLibraryCode/include_juce_data_structures.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| C858CF44E96D416E4B6B9266 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; | |||
| D352CDB4CA7E8B21FAA83B8C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MainComponent.h; path = ../../Source/MainComponent.h; sourceTree = "SOURCE_ROOT"; }; | |||
| F2CF007AA4C90AC7A5AD1604 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_analytics"; path = "../../../../modules/juce_analytics"; sourceTree = "SOURCE_ROOT"; }; | |||
| FBCE051A0BA6C9FA3E64B47B = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; | |||
| D269FA28B5D6012AEFE0BF20 = {isa = PBXGroup; children = ( | |||
| 8B927F72BA8726A064560942, | |||
| D352CDB4CA7E8B21FAA83B8C, | |||
| 6A86C9751E9DCFA62D4562DB, ); name = Source; sourceTree = "<group>"; }; | |||
| 2B971235E85DF9D98B6FC8AF = {isa = PBXGroup; children = ( | |||
| D269FA28B5D6012AEFE0BF20, ); name = AnalyticsCollection; sourceTree = "<group>"; }; | |||
| 0B35DCE65DF34DECBF1D8118 = {isa = PBXGroup; children = ( | |||
| F2CF007AA4C90AC7A5AD1604, | |||
| 02589D465A73E0112B97BD3A, | |||
| 996BEF5ADCE2EC85EB9F637F, | |||
| 1AA9DA887BE127DCED5228BB, | |||
| 886AEA380A40C905503764EB, | |||
| 5219A3D3BECB8C7135C90377, ); name = "Juce Modules"; sourceTree = "<group>"; }; | |||
| B24D9AE60E0CE5D1A75693B5 = {isa = PBXGroup; children = ( | |||
| 8A74F3F7422C89A897D93397, | |||
| 33B9806EFA95DA05ACD9344E, | |||
| 5DC0FF6BC4AE24FABC41F20E, | |||
| AD2CFF58DA5E1C6EDF9CC399, | |||
| A0DDFB3559C431E96EC59392, | |||
| 61FADB63565026F559F43F3B, | |||
| 65311EED96DCA9B62EBFEA04, | |||
| 91208A06115D573563996967, ); name = "Juce Library Code"; sourceTree = "<group>"; }; | |||
| 782C3BD0C802236A266FDEDD = {isa = PBXGroup; children = ( | |||
| 7A9FA859A2C2AE9FDDC99AD9, | |||
| 3D44D3C7CC1020729BBF62BB, ); name = Resources; sourceTree = "<group>"; }; | |||
| F70B9CB615E26A697D2CBEB4 = {isa = PBXGroup; children = ( | |||
| 570EA8E9B2BD490DAA35F86E, | |||
| C858CF44E96D416E4B6B9266, | |||
| 08EEB00E1779867598046EB6, | |||
| FBCE051A0BA6C9FA3E64B47B, ); name = Frameworks; sourceTree = "<group>"; }; | |||
| 40E8A594A7EAFA1EF5707952 = {isa = PBXGroup; children = ( | |||
| 707149C59A1AF9752E428B97, ); name = Products; sourceTree = "<group>"; }; | |||
| 5CB45B3816ED17D0620DDEBF = {isa = PBXGroup; children = ( | |||
| 2B971235E85DF9D98B6FC8AF, | |||
| 0B35DCE65DF34DECBF1D8118, | |||
| B24D9AE60E0CE5D1A75693B5, | |||
| 782C3BD0C802236A266FDEDD, | |||
| F70B9CB615E26A697D2CBEB4, | |||
| 40E8A594A7EAFA1EF5707952, ); name = Source; sourceTree = "<group>"; }; | |||
| 6FF8E864589AD3C2C06BF546 = {isa = XCBuildConfiguration; buildSettings = { | |||
| CLANG_CXX_LANGUAGE_STANDARD = "c++11"; | |||
| CLANG_LINK_OBJC_RUNTIME = NO; | |||
| COMBINE_HIDPI_IMAGES = YES; | |||
| CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; | |||
| COPY_PHASE_STRIP = NO; | |||
| GCC_DYNAMIC_NO_PIC = NO; | |||
| GCC_OPTIMIZATION_LEVEL = 0; | |||
| GCC_PREPROCESSOR_DEFINITIONS = ( | |||
| "_DEBUG=1", | |||
| "DEBUG=1", | |||
| "JUCER_XCODE_MAC_F6D2F4CF=1", | |||
| "JUCE_APP_VERSION=1.0.0", | |||
| "JUCE_APP_VERSION_HEX=0x10000", | |||
| "JucePlugin_Build_VST=0", | |||
| "JucePlugin_Build_VST3=0", | |||
| "JucePlugin_Build_AU=0", | |||
| "JucePlugin_Build_AUv3=0", | |||
| "JucePlugin_Build_RTAS=0", | |||
| "JucePlugin_Build_AAX=0", | |||
| "JucePlugin_Build_Standalone=0", ); | |||
| GCC_VERSION = com.apple.compilers.llvm.clang.1_0; | |||
| HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "$(inherited)"); | |||
| INFOPLIST_FILE = Info-App.plist; | |||
| INFOPLIST_PREPROCESS = NO; | |||
| INSTALL_PATH = "$(HOME)/Applications"; | |||
| MACOSX_DEPLOYMENT_TARGET = 10.11; | |||
| MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; | |||
| PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.AnalyticsCollection; | |||
| SDKROOT_ppc = macosx10.5; | |||
| USE_HEADERMAP = NO; }; name = Debug; }; | |||
| 8575FCD908F2B0E4E641C1A0 = {isa = XCBuildConfiguration; buildSettings = { | |||
| CLANG_CXX_LANGUAGE_STANDARD = "c++11"; | |||
| CLANG_LINK_OBJC_RUNTIME = NO; | |||
| COMBINE_HIDPI_IMAGES = YES; | |||
| CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; | |||
| DEAD_CODE_STRIPPING = YES; | |||
| GCC_GENERATE_DEBUGGING_SYMBOLS = NO; | |||
| GCC_OPTIMIZATION_LEVEL = 3; | |||
| GCC_PREPROCESSOR_DEFINITIONS = ( | |||
| "_NDEBUG=1", | |||
| "NDEBUG=1", | |||
| "JUCER_XCODE_MAC_F6D2F4CF=1", | |||
| "JUCE_APP_VERSION=1.0.0", | |||
| "JUCE_APP_VERSION_HEX=0x10000", | |||
| "JucePlugin_Build_VST=0", | |||
| "JucePlugin_Build_VST3=0", | |||
| "JucePlugin_Build_AU=0", | |||
| "JucePlugin_Build_AUv3=0", | |||
| "JucePlugin_Build_RTAS=0", | |||
| "JucePlugin_Build_AAX=0", | |||
| "JucePlugin_Build_Standalone=0", ); | |||
| GCC_SYMBOLS_PRIVATE_EXTERN = YES; | |||
| GCC_VERSION = com.apple.compilers.llvm.clang.1_0; | |||
| HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "$(inherited)"); | |||
| INFOPLIST_FILE = Info-App.plist; | |||
| INFOPLIST_PREPROCESS = NO; | |||
| INSTALL_PATH = "$(HOME)/Applications"; | |||
| MACOSX_DEPLOYMENT_TARGET = 10.11; | |||
| MACOSX_DEPLOYMENT_TARGET_ppc = 10.4; | |||
| PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.AnalyticsCollection; | |||
| SDKROOT_ppc = macosx10.5; | |||
| USE_HEADERMAP = NO; }; name = Release; }; | |||
| 0399310F2F5034CFCB14437B = {isa = XCBuildConfiguration; buildSettings = { | |||
| ALWAYS_SEARCH_USER_PATHS = NO; | |||
| CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | |||
| CLANG_WARN_BOOL_CONVERSION = YES; | |||
| CLANG_WARN_COMMA = YES; | |||
| CLANG_WARN_CONSTANT_CONVERSION = YES; | |||
| CLANG_WARN_EMPTY_BODY = YES; | |||
| CLANG_WARN_ENUM_CONVERSION = YES; | |||
| CLANG_WARN_INFINITE_RECURSION = YES; | |||
| CLANG_WARN_INT_CONVERSION = YES; | |||
| CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | |||
| CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | |||
| CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | |||
| CLANG_WARN_STRICT_PROTOTYPES = YES; | |||
| CLANG_WARN_SUSPICIOUS_MOVE = YES; | |||
| CLANG_WARN_UNREACHABLE_CODE = YES; | |||
| CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |||
| DEBUG_INFORMATION_FORMAT = "dwarf"; | |||
| ENABLE_STRICT_OBJC_MSGSEND = YES; | |||
| ENABLE_TESTABILITY = YES; | |||
| GCC_C_LANGUAGE_STANDARD = c11; | |||
| GCC_INLINES_ARE_PRIVATE_EXTERN = YES; | |||
| GCC_MODEL_TUNING = G5; | |||
| GCC_NO_COMMON_BLOCKS = YES; | |||
| GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |||
| GCC_WARN_ABOUT_RETURN_TYPE = YES; | |||
| GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; | |||
| GCC_WARN_MISSING_PARENTHESES = YES; | |||
| GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; | |||
| GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; | |||
| GCC_WARN_UNDECLARED_SELECTOR = YES; | |||
| GCC_WARN_UNINITIALIZED_AUTOS = YES; | |||
| GCC_WARN_UNUSED_FUNCTION = YES; | |||
| GCC_WARN_UNUSED_VARIABLE = YES; | |||
| ONLY_ACTIVE_ARCH = YES; | |||
| PRODUCT_NAME = "AnalyticsCollection"; | |||
| WARNING_CFLAGS = -Wreorder; | |||
| ZERO_LINK = NO; }; name = Debug; }; | |||
| D9987A1AC287063A4E090185 = {isa = XCBuildConfiguration; buildSettings = { | |||
| ALWAYS_SEARCH_USER_PATHS = NO; | |||
| CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | |||
| CLANG_WARN_BOOL_CONVERSION = YES; | |||
| CLANG_WARN_COMMA = YES; | |||
| CLANG_WARN_CONSTANT_CONVERSION = YES; | |||
| CLANG_WARN_EMPTY_BODY = YES; | |||
| CLANG_WARN_ENUM_CONVERSION = YES; | |||
| CLANG_WARN_INFINITE_RECURSION = YES; | |||
| CLANG_WARN_INT_CONVERSION = YES; | |||
| CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | |||
| CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | |||
| CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | |||
| CLANG_WARN_STRICT_PROTOTYPES = YES; | |||
| CLANG_WARN_SUSPICIOUS_MOVE = YES; | |||
| CLANG_WARN_UNREACHABLE_CODE = YES; | |||
| CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |||
| DEBUG_INFORMATION_FORMAT = "dwarf"; | |||
| ENABLE_STRICT_OBJC_MSGSEND = YES; | |||
| GCC_C_LANGUAGE_STANDARD = c11; | |||
| GCC_INLINES_ARE_PRIVATE_EXTERN = YES; | |||
| GCC_MODEL_TUNING = G5; | |||
| GCC_NO_COMMON_BLOCKS = YES; | |||
| GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |||
| GCC_WARN_ABOUT_RETURN_TYPE = YES; | |||
| GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; | |||
| GCC_WARN_MISSING_PARENTHESES = YES; | |||
| GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; | |||
| GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; | |||
| GCC_WARN_UNDECLARED_SELECTOR = YES; | |||
| GCC_WARN_UNINITIALIZED_AUTOS = YES; | |||
| GCC_WARN_UNUSED_FUNCTION = YES; | |||
| GCC_WARN_UNUSED_VARIABLE = YES; | |||
| PRODUCT_NAME = "AnalyticsCollection"; | |||
| WARNING_CFLAGS = -Wreorder; | |||
| ZERO_LINK = NO; }; name = Release; }; | |||
| E1B8C9CDDA25A31AA3C9C1BC = {isa = PBXTargetDependency; target = 3195ADB3A101AAE977C998D2; }; | |||
| 65535D1056F6B2C9C545923E = {isa = XCConfigurationList; buildConfigurations = ( | |||
| 0399310F2F5034CFCB14437B, | |||
| D9987A1AC287063A4E090185, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; | |||
| 850BB95DDE68E87344778037 = {isa = XCConfigurationList; buildConfigurations = ( | |||
| 6FF8E864589AD3C2C06BF546, | |||
| 8575FCD908F2B0E4E641C1A0, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; | |||
| 9DE971716CBA79E89467EFD0 = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( | |||
| A0DA914E3E16F49D60A5A47F, ); runOnlyForDeploymentPostprocessing = 0; }; | |||
| A01C1A7AFBB72E638096E0BA = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( | |||
| D293FC19C031441D146F2410, | |||
| 962036B1BB2EDB0F9D53E125, | |||
| 6297B7A712B1E5A74311F162, | |||
| 132F9FBC9EB36AF2E755325D, | |||
| 805CDCC5840B0D713C286826, | |||
| C09B5A3CD0643CF37C9CF851, | |||
| A1DF340E80EC501B1DBE75A0, ); runOnlyForDeploymentPostprocessing = 0; }; | |||
| 32F46511CABBD859FD1D427D = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( | |||
| B45E888BC48139CA81112E4A, | |||
| 375013DDDA026F2709E4FDAD, | |||
| 877F68400FB5A15B39719C61, | |||
| 38EE4929FFB8B83FB37B6E73, ); runOnlyForDeploymentPostprocessing = 0; }; | |||
| 3195ADB3A101AAE977C998D2 = {isa = PBXNativeTarget; buildConfigurationList = 850BB95DDE68E87344778037; buildPhases = ( | |||
| 9DE971716CBA79E89467EFD0, | |||
| A01C1A7AFBB72E638096E0BA, | |||
| 32F46511CABBD859FD1D427D, ); buildRules = ( ); dependencies = ( ); name = "AnalyticsCollection - App"; productName = AnalyticsCollection; productReference = 707149C59A1AF9752E428B97; productType = "com.apple.product-type.application"; }; | |||
| 8C6201B9CB81795542E3302D = {isa = PBXProject; buildConfigurationList = 65535D1056F6B2C9C545923E; attributes = { LastUpgradeCheck = 0830; TargetAttributes = { 3195ADB3A101AAE977C998D2 = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; }; }; }; compatibilityVersion = "Xcode 3.2"; hasScannedForEncodings = 0; mainGroup = 5CB45B3816ED17D0620DDEBF; projectDirPath = ""; projectRoot = ""; targets = (3195ADB3A101AAE977C998D2); }; | |||
| }; | |||
| rootObject = 8C6201B9CB81795542E3302D; | |||
| } | |||
| @@ -0,0 +1,29 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
| <plist> | |||
| <dict> | |||
| <key>CFBundleExecutable</key> | |||
| <string>${EXECUTABLE_NAME}</string> | |||
| <key>CFBundleIconFile</key> | |||
| <string></string> | |||
| <key>CFBundleIdentifier</key> | |||
| <string>com.yourcompany.AnalyticsCollection</string> | |||
| <key>CFBundleName</key> | |||
| <string>AnalyticsCollection</string> | |||
| <key>CFBundleDisplayName</key> | |||
| <string>AnalyticsCollection</string> | |||
| <key>CFBundlePackageType</key> | |||
| <string>APPL</string> | |||
| <key>CFBundleSignature</key> | |||
| <string>????</string> | |||
| <key>CFBundleShortVersionString</key> | |||
| <string>1.0.0</string> | |||
| <key>CFBundleVersion</key> | |||
| <string>1.0.0</string> | |||
| <key>NSHumanReadableCopyright</key> | |||
| <string></string> | |||
| <key>NSHighResolutionCapable</key> | |||
| <true/> | |||
| </dict> | |||
| </plist> | |||
| @@ -0,0 +1,20 @@ | |||
| Microsoft Visual Studio Solution File, Format Version 11.00 | |||
| # Visual Studio 2017 | |||
| Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnalyticsCollection - App", "AnalyticsCollection_App.vcxproj", "{C52D63D2-B7D8-F34E-1B84-186CB9D963EB}" | |||
| EndProject | |||
| Global | |||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
| Debug|x64 = Debug|x64 | |||
| Release|x64 = Release|x64 | |||
| EndGlobalSection | |||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
| {C52D63D2-B7D8-F34E-1B84-186CB9D963EB}.Debug|x64.ActiveCfg = Debug|x64 | |||
| {C52D63D2-B7D8-F34E-1B84-186CB9D963EB}.Debug|x64.Build.0 = Debug|x64 | |||
| {C52D63D2-B7D8-F34E-1B84-186CB9D963EB}.Release|x64.ActiveCfg = Release|x64 | |||
| {C52D63D2-B7D8-F34E-1B84-186CB9D963EB}.Release|x64.Build.0 = Release|x64 | |||
| EndGlobalSection | |||
| GlobalSection(SolutionProperties) = preSolution | |||
| HideSolutionNode = FALSE | |||
| EndGlobalSection | |||
| EndGlobal | |||
| @@ -0,0 +1,29 @@ | |||
| #ifdef JUCE_USER_DEFINED_RC_FILE | |||
| #include JUCE_USER_DEFINED_RC_FILE | |||
| #else | |||
| #undef WIN32_LEAN_AND_MEAN | |||
| #define WIN32_LEAN_AND_MEAN | |||
| #include <windows.h> | |||
| VS_VERSION_INFO VERSIONINFO | |||
| FILEVERSION 1,0,0,0 | |||
| BEGIN | |||
| BLOCK "StringFileInfo" | |||
| BEGIN | |||
| BLOCK "040904E4" | |||
| BEGIN | |||
| VALUE "FileDescription", "AnalyticsCollection\0" | |||
| VALUE "FileVersion", "1.0.0\0" | |||
| VALUE "ProductName", "AnalyticsCollection\0" | |||
| VALUE "ProductVersion", "1.0.0\0" | |||
| END | |||
| END | |||
| BLOCK "VarFileInfo" | |||
| BEGIN | |||
| VALUE "Translation", 0x409, 1252 | |||
| END | |||
| END | |||
| #endif | |||
| @@ -0,0 +1,265 @@ | |||
| // !$*UTF8*$! | |||
| { | |||
| archiveVersion = 1; | |||
| classes = { | |||
| }; | |||
| objectVersion = 46; | |||
| objects = { | |||
| 95AA57DF380DDDCD099D4000 = {isa = PBXBuildFile; fileRef = 707149C59A1AF9752E428B97; }; | |||
| F7E415084D290C237F9E638A = {isa = PBXBuildFile; fileRef = A93F5541F6B3C067538499EF; }; | |||
| A808E8D738B9BD079492797F = {isa = PBXBuildFile; fileRef = D87EBFBF8CF2D8160F22405B; }; | |||
| 921F2D865DD5EBF5AA00DF38 = {isa = PBXBuildFile; fileRef = 644905C665C9F08A8700FE0D; }; | |||
| 107547912F5D18FB3DD33009 = {isa = PBXBuildFile; fileRef = 192797C933B56812538409D4; }; | |||
| 38EE4929FFB8B83FB37B6E73 = {isa = PBXBuildFile; fileRef = FBCE051A0BA6C9FA3E64B47B; }; | |||
| F6BB4E84E37BD38B6CA3025E = {isa = PBXBuildFile; fileRef = E206CE5D6771CAAA3C56F465; }; | |||
| 02E32ED5F96146B51FE4669C = {isa = PBXBuildFile; fileRef = BC02966C48A4F51E9A187E4A; }; | |||
| D293FC19C031441D146F2410 = {isa = PBXBuildFile; fileRef = 6A86C9751E9DCFA62D4562DB; }; | |||
| 962036B1BB2EDB0F9D53E125 = {isa = PBXBuildFile; fileRef = 33B9806EFA95DA05ACD9344E; }; | |||
| 6297B7A712B1E5A74311F162 = {isa = PBXBuildFile; fileRef = 5DC0FF6BC4AE24FABC41F20E; }; | |||
| 132F9FBC9EB36AF2E755325D = {isa = PBXBuildFile; fileRef = AD2CFF58DA5E1C6EDF9CC399; }; | |||
| 805CDCC5840B0D713C286826 = {isa = PBXBuildFile; fileRef = A0DDFB3559C431E96EC59392; }; | |||
| C09B5A3CD0643CF37C9CF851 = {isa = PBXBuildFile; fileRef = 61FADB63565026F559F43F3B; }; | |||
| A1DF340E80EC501B1DBE75A0 = {isa = PBXBuildFile; fileRef = 65311EED96DCA9B62EBFEA04; }; | |||
| 02589D465A73E0112B97BD3A = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_core"; path = "../../../../modules/juce_core"; sourceTree = "SOURCE_ROOT"; }; | |||
| 192797C933B56812538409D4 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; | |||
| 1AA9DA887BE127DCED5228BB = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_events"; path = "../../../../modules/juce_events"; sourceTree = "SOURCE_ROOT"; }; | |||
| 33B9806EFA95DA05ACD9344E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "include_juce_analytics.cpp"; path = "../../JuceLibraryCode/include_juce_analytics.cpp"; sourceTree = "SOURCE_ROOT"; }; | |||
| 5219A3D3BECB8C7135C90377 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_gui_basics"; path = "../../../../modules/juce_gui_basics"; sourceTree = "SOURCE_ROOT"; }; | |||
| 5DC0FF6BC4AE24FABC41F20E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_core.mm"; path = "../../JuceLibraryCode/include_juce_core.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| 61FADB63565026F559F43F3B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_graphics.mm"; path = "../../JuceLibraryCode/include_juce_graphics.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| 644905C665C9F08A8700FE0D = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; | |||
| 65311EED96DCA9B62EBFEA04 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_gui_basics.mm"; path = "../../JuceLibraryCode/include_juce_gui_basics.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| 6A86C9751E9DCFA62D4562DB = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Main.cpp; path = ../../Source/Main.cpp; sourceTree = "SOURCE_ROOT"; }; | |||
| 707149C59A1AF9752E428B97 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnalyticsCollection.app; sourceTree = "BUILT_PRODUCTS_DIR"; }; | |||
| 7A9FA859A2C2AE9FDDC99AD9 = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Info-App.plist"; path = "Info-App.plist"; sourceTree = "SOURCE_ROOT"; }; | |||
| 886AEA380A40C905503764EB = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_graphics"; path = "../../../../modules/juce_graphics"; sourceTree = "SOURCE_ROOT"; }; | |||
| 8A74F3F7422C89A897D93397 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppConfig.h; path = ../../JuceLibraryCode/AppConfig.h; sourceTree = "SOURCE_ROOT"; }; | |||
| 8B927F72BA8726A064560942 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GoogleAnalyticsDestination.h; path = ../../Source/GoogleAnalyticsDestination.h; sourceTree = "SOURCE_ROOT"; }; | |||
| 91208A06115D573563996967 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JuceHeader.h; path = ../../JuceLibraryCode/JuceHeader.h; sourceTree = "SOURCE_ROOT"; }; | |||
| 996BEF5ADCE2EC85EB9F637F = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_data_structures"; path = "../../../../modules/juce_data_structures"; sourceTree = "SOURCE_ROOT"; }; | |||
| A0DDFB3559C431E96EC59392 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_events.mm"; path = "../../JuceLibraryCode/include_juce_events.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| A93F5541F6B3C067538499EF = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; | |||
| AD2CFF58DA5E1C6EDF9CC399 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "include_juce_data_structures.mm"; path = "../../JuceLibraryCode/include_juce_data_structures.mm"; sourceTree = "SOURCE_ROOT"; }; | |||
| BC02966C48A4F51E9A187E4A = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = AnalyticsCollection/Images.xcassets; sourceTree = "SOURCE_ROOT"; }; | |||
| D352CDB4CA7E8B21FAA83B8C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MainComponent.h; path = ../../Source/MainComponent.h; sourceTree = "SOURCE_ROOT"; }; | |||
| D87EBFBF8CF2D8160F22405B = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; }; | |||
| E206CE5D6771CAAA3C56F465 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; | |||
| F2CF007AA4C90AC7A5AD1604 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_analytics"; path = "../../../../modules/juce_analytics"; sourceTree = "SOURCE_ROOT"; }; | |||
| FBCE051A0BA6C9FA3E64B47B = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; | |||
| D269FA28B5D6012AEFE0BF20 = {isa = PBXGroup; children = ( | |||
| 8B927F72BA8726A064560942, | |||
| D352CDB4CA7E8B21FAA83B8C, | |||
| 6A86C9751E9DCFA62D4562DB, ); name = Source; sourceTree = "<group>"; }; | |||
| 2B971235E85DF9D98B6FC8AF = {isa = PBXGroup; children = ( | |||
| D269FA28B5D6012AEFE0BF20, ); name = AnalyticsCollection; sourceTree = "<group>"; }; | |||
| 0B35DCE65DF34DECBF1D8118 = {isa = PBXGroup; children = ( | |||
| F2CF007AA4C90AC7A5AD1604, | |||
| 02589D465A73E0112B97BD3A, | |||
| 996BEF5ADCE2EC85EB9F637F, | |||
| 1AA9DA887BE127DCED5228BB, | |||
| 886AEA380A40C905503764EB, | |||
| 5219A3D3BECB8C7135C90377, ); name = "Juce Modules"; sourceTree = "<group>"; }; | |||
| B24D9AE60E0CE5D1A75693B5 = {isa = PBXGroup; children = ( | |||
| 8A74F3F7422C89A897D93397, | |||
| 33B9806EFA95DA05ACD9344E, | |||
| 5DC0FF6BC4AE24FABC41F20E, | |||
| AD2CFF58DA5E1C6EDF9CC399, | |||
| A0DDFB3559C431E96EC59392, | |||
| 61FADB63565026F559F43F3B, | |||
| 65311EED96DCA9B62EBFEA04, | |||
| 91208A06115D573563996967, ); name = "Juce Library Code"; sourceTree = "<group>"; }; | |||
| 782C3BD0C802236A266FDEDD = {isa = PBXGroup; children = ( | |||
| 7A9FA859A2C2AE9FDDC99AD9, | |||
| BC02966C48A4F51E9A187E4A, ); name = Resources; sourceTree = "<group>"; }; | |||
| F70B9CB615E26A697D2CBEB4 = {isa = PBXGroup; children = ( | |||
| A93F5541F6B3C067538499EF, | |||
| D87EBFBF8CF2D8160F22405B, | |||
| 644905C665C9F08A8700FE0D, | |||
| 192797C933B56812538409D4, | |||
| FBCE051A0BA6C9FA3E64B47B, | |||
| E206CE5D6771CAAA3C56F465, ); name = Frameworks; sourceTree = "<group>"; }; | |||
| 40E8A594A7EAFA1EF5707952 = {isa = PBXGroup; children = ( | |||
| 707149C59A1AF9752E428B97, ); name = Products; sourceTree = "<group>"; }; | |||
| 5CB45B3816ED17D0620DDEBF = {isa = PBXGroup; children = ( | |||
| 2B971235E85DF9D98B6FC8AF, | |||
| 0B35DCE65DF34DECBF1D8118, | |||
| B24D9AE60E0CE5D1A75693B5, | |||
| 782C3BD0C802236A266FDEDD, | |||
| F70B9CB615E26A697D2CBEB4, | |||
| 40E8A594A7EAFA1EF5707952, ); name = Source; sourceTree = "<group>"; }; | |||
| 6FF8E864589AD3C2C06BF546 = {isa = XCBuildConfiguration; buildSettings = { | |||
| ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | |||
| ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; | |||
| CLANG_CXX_LANGUAGE_STANDARD = "c++11"; | |||
| CLANG_LINK_OBJC_RUNTIME = NO; | |||
| COMBINE_HIDPI_IMAGES = YES; | |||
| CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; | |||
| COPY_PHASE_STRIP = NO; | |||
| GCC_DYNAMIC_NO_PIC = NO; | |||
| GCC_OPTIMIZATION_LEVEL = 0; | |||
| GCC_PREPROCESSOR_DEFINITIONS = ( | |||
| "_DEBUG=1", | |||
| "DEBUG=1", | |||
| "JUCER_XCODE_IPHONE_5BC26AE3=1", | |||
| "JUCE_APP_VERSION=1.0.0", | |||
| "JUCE_APP_VERSION_HEX=0x10000", | |||
| "JucePlugin_Build_VST=0", | |||
| "JucePlugin_Build_VST3=0", | |||
| "JucePlugin_Build_AU=0", | |||
| "JucePlugin_Build_AUv3=0", | |||
| "JucePlugin_Build_RTAS=0", | |||
| "JucePlugin_Build_AAX=0", | |||
| "JucePlugin_Build_Standalone=0", ); | |||
| GCC_VERSION = com.apple.compilers.llvm.clang.1_0; | |||
| HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "$(inherited)"); | |||
| INFOPLIST_FILE = Info-App.plist; | |||
| INFOPLIST_PREPROCESS = NO; | |||
| INSTALL_PATH = "$(HOME)/Applications"; | |||
| PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.AnalyticsCollection; | |||
| USE_HEADERMAP = NO; }; name = Debug; }; | |||
| 8575FCD908F2B0E4E641C1A0 = {isa = XCBuildConfiguration; buildSettings = { | |||
| ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | |||
| ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; | |||
| CLANG_CXX_LANGUAGE_STANDARD = "c++11"; | |||
| CLANG_LINK_OBJC_RUNTIME = NO; | |||
| COMBINE_HIDPI_IMAGES = YES; | |||
| CONFIGURATION_BUILD_DIR = "$(PROJECT_DIR)/build/$(CONFIGURATION)"; | |||
| DEAD_CODE_STRIPPING = YES; | |||
| GCC_GENERATE_DEBUGGING_SYMBOLS = NO; | |||
| GCC_OPTIMIZATION_LEVEL = 3; | |||
| GCC_PREPROCESSOR_DEFINITIONS = ( | |||
| "_NDEBUG=1", | |||
| "NDEBUG=1", | |||
| "JUCER_XCODE_IPHONE_5BC26AE3=1", | |||
| "JUCE_APP_VERSION=1.0.0", | |||
| "JUCE_APP_VERSION_HEX=0x10000", | |||
| "JucePlugin_Build_VST=0", | |||
| "JucePlugin_Build_VST3=0", | |||
| "JucePlugin_Build_AU=0", | |||
| "JucePlugin_Build_AUv3=0", | |||
| "JucePlugin_Build_RTAS=0", | |||
| "JucePlugin_Build_AAX=0", | |||
| "JucePlugin_Build_Standalone=0", ); | |||
| GCC_SYMBOLS_PRIVATE_EXTERN = YES; | |||
| GCC_VERSION = com.apple.compilers.llvm.clang.1_0; | |||
| HEADER_SEARCH_PATHS = ("../../JuceLibraryCode", "../../../../modules", "$(inherited)"); | |||
| INFOPLIST_FILE = Info-App.plist; | |||
| INFOPLIST_PREPROCESS = NO; | |||
| INSTALL_PATH = "$(HOME)/Applications"; | |||
| PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.AnalyticsCollection; | |||
| USE_HEADERMAP = NO; }; name = Release; }; | |||
| 0399310F2F5034CFCB14437B = {isa = XCBuildConfiguration; buildSettings = { | |||
| "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | |||
| ALWAYS_SEARCH_USER_PATHS = NO; | |||
| CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | |||
| CLANG_WARN_BOOL_CONVERSION = YES; | |||
| CLANG_WARN_COMMA = YES; | |||
| CLANG_WARN_CONSTANT_CONVERSION = YES; | |||
| CLANG_WARN_EMPTY_BODY = YES; | |||
| CLANG_WARN_ENUM_CONVERSION = YES; | |||
| CLANG_WARN_INFINITE_RECURSION = YES; | |||
| CLANG_WARN_INT_CONVERSION = YES; | |||
| CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | |||
| CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | |||
| CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | |||
| CLANG_WARN_STRICT_PROTOTYPES = YES; | |||
| CLANG_WARN_SUSPICIOUS_MOVE = YES; | |||
| CLANG_WARN_UNREACHABLE_CODE = YES; | |||
| CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |||
| DEBUG_INFORMATION_FORMAT = "dwarf"; | |||
| ENABLE_STRICT_OBJC_MSGSEND = YES; | |||
| ENABLE_TESTABILITY = YES; | |||
| GCC_C_LANGUAGE_STANDARD = c11; | |||
| GCC_INLINES_ARE_PRIVATE_EXTERN = YES; | |||
| GCC_MODEL_TUNING = G5; | |||
| GCC_NO_COMMON_BLOCKS = YES; | |||
| GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |||
| GCC_WARN_ABOUT_RETURN_TYPE = YES; | |||
| GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; | |||
| GCC_WARN_MISSING_PARENTHESES = YES; | |||
| GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; | |||
| GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; | |||
| GCC_WARN_UNDECLARED_SELECTOR = YES; | |||
| GCC_WARN_UNINITIALIZED_AUTOS = YES; | |||
| GCC_WARN_UNUSED_FUNCTION = YES; | |||
| GCC_WARN_UNUSED_VARIABLE = YES; | |||
| IPHONEOS_DEPLOYMENT_TARGET = 9.3; | |||
| ONLY_ACTIVE_ARCH = YES; | |||
| PRODUCT_NAME = "AnalyticsCollection"; | |||
| SDKROOT = iphoneos; | |||
| TARGETED_DEVICE_FAMILY = "1,2"; | |||
| WARNING_CFLAGS = -Wreorder; | |||
| ZERO_LINK = NO; }; name = Debug; }; | |||
| D9987A1AC287063A4E090185 = {isa = XCBuildConfiguration; buildSettings = { | |||
| "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | |||
| ALWAYS_SEARCH_USER_PATHS = NO; | |||
| CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | |||
| CLANG_WARN_BOOL_CONVERSION = YES; | |||
| CLANG_WARN_COMMA = YES; | |||
| CLANG_WARN_CONSTANT_CONVERSION = YES; | |||
| CLANG_WARN_EMPTY_BODY = YES; | |||
| CLANG_WARN_ENUM_CONVERSION = YES; | |||
| CLANG_WARN_INFINITE_RECURSION = YES; | |||
| CLANG_WARN_INT_CONVERSION = YES; | |||
| CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | |||
| CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | |||
| CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | |||
| CLANG_WARN_STRICT_PROTOTYPES = YES; | |||
| CLANG_WARN_SUSPICIOUS_MOVE = YES; | |||
| CLANG_WARN_UNREACHABLE_CODE = YES; | |||
| CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |||
| DEBUG_INFORMATION_FORMAT = "dwarf"; | |||
| ENABLE_STRICT_OBJC_MSGSEND = YES; | |||
| GCC_C_LANGUAGE_STANDARD = c11; | |||
| GCC_INLINES_ARE_PRIVATE_EXTERN = YES; | |||
| GCC_MODEL_TUNING = G5; | |||
| GCC_NO_COMMON_BLOCKS = YES; | |||
| GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |||
| GCC_WARN_ABOUT_RETURN_TYPE = YES; | |||
| GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; | |||
| GCC_WARN_MISSING_PARENTHESES = YES; | |||
| GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; | |||
| GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; | |||
| GCC_WARN_UNDECLARED_SELECTOR = YES; | |||
| GCC_WARN_UNINITIALIZED_AUTOS = YES; | |||
| GCC_WARN_UNUSED_FUNCTION = YES; | |||
| GCC_WARN_UNUSED_VARIABLE = YES; | |||
| IPHONEOS_DEPLOYMENT_TARGET = 9.3; | |||
| PRODUCT_NAME = "AnalyticsCollection"; | |||
| SDKROOT = iphoneos; | |||
| TARGETED_DEVICE_FAMILY = "1,2"; | |||
| WARNING_CFLAGS = -Wreorder; | |||
| ZERO_LINK = NO; }; name = Release; }; | |||
| E1B8C9CDDA25A31AA3C9C1BC = {isa = PBXTargetDependency; target = 3195ADB3A101AAE977C998D2; }; | |||
| 65535D1056F6B2C9C545923E = {isa = XCConfigurationList; buildConfigurations = ( | |||
| 0399310F2F5034CFCB14437B, | |||
| D9987A1AC287063A4E090185, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; | |||
| 850BB95DDE68E87344778037 = {isa = XCConfigurationList; buildConfigurations = ( | |||
| 6FF8E864589AD3C2C06BF546, | |||
| 8575FCD908F2B0E4E641C1A0, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; | |||
| 9DE971716CBA79E89467EFD0 = {isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( | |||
| 02E32ED5F96146B51FE4669C, ); runOnlyForDeploymentPostprocessing = 0; }; | |||
| A01C1A7AFBB72E638096E0BA = {isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( | |||
| D293FC19C031441D146F2410, | |||
| 962036B1BB2EDB0F9D53E125, | |||
| 6297B7A712B1E5A74311F162, | |||
| 132F9FBC9EB36AF2E755325D, | |||
| 805CDCC5840B0D713C286826, | |||
| C09B5A3CD0643CF37C9CF851, | |||
| A1DF340E80EC501B1DBE75A0, ); runOnlyForDeploymentPostprocessing = 0; }; | |||
| 32F46511CABBD859FD1D427D = {isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( | |||
| F7E415084D290C237F9E638A, | |||
| A808E8D738B9BD079492797F, | |||
| 921F2D865DD5EBF5AA00DF38, | |||
| 107547912F5D18FB3DD33009, | |||
| 38EE4929FFB8B83FB37B6E73, | |||
| F6BB4E84E37BD38B6CA3025E, ); runOnlyForDeploymentPostprocessing = 0; }; | |||
| 3195ADB3A101AAE977C998D2 = {isa = PBXNativeTarget; buildConfigurationList = 850BB95DDE68E87344778037; buildPhases = ( | |||
| 9DE971716CBA79E89467EFD0, | |||
| A01C1A7AFBB72E638096E0BA, | |||
| 32F46511CABBD859FD1D427D, ); buildRules = ( ); dependencies = ( ); name = "AnalyticsCollection - App"; productName = AnalyticsCollection; productReference = 707149C59A1AF9752E428B97; productType = "com.apple.product-type.application"; }; | |||
| 8C6201B9CB81795542E3302D = {isa = PBXProject; buildConfigurationList = 65535D1056F6B2C9C545923E; attributes = { LastUpgradeCheck = 0830; TargetAttributes = { 3195ADB3A101AAE977C998D2 = { SystemCapabilities = {com.apple.ApplicationGroups.iOS = { enabled = 0; }; com.apple.InAppPurchase = { enabled = 0; }; com.apple.InterAppAudio = { enabled = 0; }; com.apple.Push = { enabled = 0; }; com.apple.Sandbox = { enabled = 0; }; }; }; }; }; compatibilityVersion = "Xcode 3.2"; hasScannedForEncodings = 0; mainGroup = 5CB45B3816ED17D0620DDEBF; projectDirPath = ""; projectRoot = ""; targets = (3195ADB3A101AAE977C998D2); }; | |||
| }; | |||
| rootObject = 8C6201B9CB81795542E3302D; | |||
| } | |||
| @@ -0,0 +1,158 @@ | |||
| { | |||
| "images": [ | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "20x20", | |||
| "filename": "Icon-Notification-20@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "20x20", | |||
| "filename": "Icon-Notification-20@3x.png", | |||
| "scale": "3x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "29x29", | |||
| "filename": "Icon-29.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "29x29", | |||
| "filename": "Icon-29@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "29x29", | |||
| "filename": "Icon-29@3x.png", | |||
| "scale": "3x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "40x40", | |||
| "filename": "Icon-Spotlight-40@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "40x40", | |||
| "filename": "Icon-Spotlight-40@3x.png", | |||
| "scale": "3x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "57x57", | |||
| "filename": "Icon.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "57x57", | |||
| "filename": "Icon@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "60x60", | |||
| "filename": "Icon-60@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "iphone", | |||
| "size": "60x60", | |||
| "filename": "Icon-@3x.png", | |||
| "scale": "3x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "20x20", | |||
| "filename": "Icon-Notifications-20.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "20x20", | |||
| "filename": "Icon-Notifications-20@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "29x29", | |||
| "filename": "Icon-Small-1.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "29x29", | |||
| "filename": "Icon-Small@2x-1.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "40x40", | |||
| "filename": "Icon-Spotlight-40.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "40x40", | |||
| "filename": "Icon-Spotlight-40@2x-1.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "50x50", | |||
| "filename": "Icon-Small-50.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "50x50", | |||
| "filename": "Icon-Small-50@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "72x72", | |||
| "filename": "Icon-72.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "72x72", | |||
| "filename": "Icon-72@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "76x76", | |||
| "filename": "Icon-76.png", | |||
| "scale": "1x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "76x76", | |||
| "filename": "Icon-76@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ipad", | |||
| "size": "83.5x83.5", | |||
| "filename": "Icon-83.5@2x.png", | |||
| "scale": "2x" | |||
| }, | |||
| { | |||
| "idiom": "ios-marketing", | |||
| "size": "1024x1024", | |||
| "filename": "Icon-AppStore-1024.png", | |||
| "scale": "1x" | |||
| } | |||
| ], | |||
| "info": { | |||
| "version": 1, | |||
| "author": "xcode" | |||
| } | |||
| } | |||
| @@ -0,0 +1,57 @@ | |||
| { | |||
| "images": [ | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "iphone", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x", | |||
| "filename": "LaunchImage-iphone-2x.png" | |||
| }, | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "iphone", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x", | |||
| "filename": "LaunchImage-iphone-retina4.png", | |||
| "subtype": "retina4" | |||
| }, | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "1x", | |||
| "filename": "LaunchImage-ipad-portrait-1x.png" | |||
| }, | |||
| { | |||
| "orientation": "landscape", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "1x", | |||
| "filename": "LaunchImage-ipad-landscape-1x.png" | |||
| }, | |||
| { | |||
| "orientation": "portrait", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x", | |||
| "filename": "LaunchImage-ipad-portrait-2x.png" | |||
| }, | |||
| { | |||
| "orientation": "landscape", | |||
| "idiom": "ipad", | |||
| "extent": "full-screen", | |||
| "minimum-system-version": "7.0", | |||
| "scale": "2x", | |||
| "filename": "LaunchImage-ipad-landscape-2x.png" | |||
| } | |||
| ], | |||
| "info": { | |||
| "version": 1, | |||
| "author": "xcode" | |||
| } | |||
| } | |||
| @@ -0,0 +1,43 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
| <plist> | |||
| <dict> | |||
| <key>LSRequiresIPhoneOS</key> | |||
| <true/> | |||
| <key>UIViewControllerBasedStatusBarAppearance</key> | |||
| <false/> | |||
| <key>CFBundleExecutable</key> | |||
| <string>${EXECUTABLE_NAME}</string> | |||
| <key>CFBundleIdentifier</key> | |||
| <string>com.yourcompany.AnalyticsCollection</string> | |||
| <key>CFBundleName</key> | |||
| <string>AnalyticsCollection</string> | |||
| <key>CFBundleDisplayName</key> | |||
| <string>AnalyticsCollection</string> | |||
| <key>CFBundlePackageType</key> | |||
| <string>APPL</string> | |||
| <key>CFBundleSignature</key> | |||
| <string>????</string> | |||
| <key>CFBundleShortVersionString</key> | |||
| <string>1.0.0</string> | |||
| <key>CFBundleVersion</key> | |||
| <string>1.0.0</string> | |||
| <key>NSHumanReadableCopyright</key> | |||
| <string></string> | |||
| <key>NSHighResolutionCapable</key> | |||
| <true/> | |||
| <key>UIRequiresFullScreen</key> | |||
| <true/> | |||
| <key>UIStatusBarHidden</key> | |||
| <true/> | |||
| <key>UISupportedInterfaceOrientations</key> | |||
| <array> | |||
| <string>UIInterfaceOrientationPortrait</string> | |||
| <string>UIInterfaceOrientationLandscapeLeft</string> | |||
| <string>UIInterfaceOrientationLandscapeRight</string> | |||
| </array> | |||
| <key>UIBackgroundModes</key> | |||
| <array/> | |||
| </dict> | |||
| </plist> | |||
| @@ -0,0 +1,138 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| There's a section below where you can add your own custom code safely, and the | |||
| Projucer will preserve the contents of that block, but the best way to change | |||
| any of these definitions is by using the Projucer's project settings. | |||
| Any commented-out settings will assume their default values. | |||
| */ | |||
| #pragma once | |||
| //============================================================================== | |||
| // [BEGIN_USER_CODE_SECTION] | |||
| // (You can add your own code in this section, and the Projucer will not overwrite it) | |||
| // [END_USER_CODE_SECTION] | |||
| /* | |||
| ============================================================================== | |||
| In accordance with the terms of the JUCE 5 End-Use License Agreement, the | |||
| JUCE Code in SECTION A cannot be removed, changed or otherwise rendered | |||
| ineffective unless you have a JUCE Indie or Pro license, or are using JUCE | |||
| under the GPL v3 license. | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| ============================================================================== | |||
| */ | |||
| // BEGIN SECTION A | |||
| #ifndef JUCE_DISPLAY_SPLASH_SCREEN | |||
| #define JUCE_DISPLAY_SPLASH_SCREEN 0 | |||
| #endif | |||
| #ifndef JUCE_REPORT_APP_USAGE | |||
| #define JUCE_REPORT_APP_USAGE 0 | |||
| #endif | |||
| // END SECTION A | |||
| #define JUCE_USE_DARK_SPLASH_SCREEN 1 | |||
| //============================================================================== | |||
| #define JUCE_MODULE_AVAILABLE_juce_analytics 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_core 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_data_structures 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_events 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_graphics 1 | |||
| #define JUCE_MODULE_AVAILABLE_juce_gui_basics 1 | |||
| #define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1 | |||
| //============================================================================== | |||
| // juce_core flags: | |||
| #ifndef JUCE_FORCE_DEBUG | |||
| //#define JUCE_FORCE_DEBUG 1 | |||
| #endif | |||
| #ifndef JUCE_LOG_ASSERTIONS | |||
| //#define JUCE_LOG_ASSERTIONS 1 | |||
| #endif | |||
| #ifndef JUCE_CHECK_MEMORY_LEAKS | |||
| //#define JUCE_CHECK_MEMORY_LEAKS 1 | |||
| #endif | |||
| #ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES | |||
| //#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 1 | |||
| #endif | |||
| #ifndef JUCE_INCLUDE_ZLIB_CODE | |||
| //#define JUCE_INCLUDE_ZLIB_CODE 1 | |||
| #endif | |||
| #ifndef JUCE_USE_CURL | |||
| //#define JUCE_USE_CURL 1 | |||
| #endif | |||
| #ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS | |||
| //#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 | |||
| #endif | |||
| #ifndef JUCE_ALLOW_STATIC_NULL_VARIABLES | |||
| //#define JUCE_ALLOW_STATIC_NULL_VARIABLES 1 | |||
| #endif | |||
| //============================================================================== | |||
| // juce_events flags: | |||
| #ifndef JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK | |||
| //#define JUCE_EXECUTE_APP_SUSPEND_ON_IOS_BACKGROUND_TASK 1 | |||
| #endif | |||
| //============================================================================== | |||
| // juce_graphics flags: | |||
| #ifndef JUCE_USE_COREIMAGE_LOADER | |||
| //#define JUCE_USE_COREIMAGE_LOADER 1 | |||
| #endif | |||
| #ifndef JUCE_USE_DIRECTWRITE | |||
| //#define JUCE_USE_DIRECTWRITE 1 | |||
| #endif | |||
| //============================================================================== | |||
| // juce_gui_basics flags: | |||
| #ifndef JUCE_ENABLE_REPAINT_DEBUGGING | |||
| //#define JUCE_ENABLE_REPAINT_DEBUGGING 1 | |||
| #endif | |||
| #ifndef JUCE_USE_XSHM | |||
| //#define JUCE_USE_XSHM 1 | |||
| #endif | |||
| #ifndef JUCE_USE_XRENDER | |||
| //#define JUCE_USE_XRENDER 1 | |||
| #endif | |||
| #ifndef JUCE_USE_XCURSOR | |||
| //#define JUCE_USE_XCURSOR 1 | |||
| #endif | |||
| //============================================================================== | |||
| #ifndef JUCE_STANDALONE_APPLICATION | |||
| #if defined(JucePlugin_Name) && defined(JucePlugin_Build_Standalone) | |||
| #define JUCE_STANDALONE_APPLICATION JucePlugin_Build_Standalone | |||
| #else | |||
| #define JUCE_STANDALONE_APPLICATION 1 | |||
| #endif | |||
| #endif | |||
| @@ -0,0 +1,38 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| This is the header file that your files should include in order to get all the | |||
| JUCE library headers. You should avoid including the JUCE headers directly in | |||
| your own source files, because that wouldn't pick up the correct configuration | |||
| options for your app. | |||
| */ | |||
| #pragma once | |||
| #include "AppConfig.h" | |||
| #include <juce_analytics/juce_analytics.h> | |||
| #include <juce_core/juce_core.h> | |||
| #include <juce_data_structures/juce_data_structures.h> | |||
| #include <juce_events/juce_events.h> | |||
| #include <juce_graphics/juce_graphics.h> | |||
| #include <juce_gui_basics/juce_gui_basics.h> | |||
| #if ! DONT_SET_USING_JUCE_NAMESPACE | |||
| // If your code uses a lot of JUCE classes, then this will obviously save you | |||
| // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. | |||
| using namespace juce; | |||
| #endif | |||
| #if ! JUCE_DONT_DECLARE_PROJECTINFO | |||
| namespace ProjectInfo | |||
| { | |||
| const char* const projectName = "AnalyticsCollection"; | |||
| const char* const versionString = "1.0.0"; | |||
| const int versionNumber = 0x10000; | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,12 @@ | |||
| Important Note!! | |||
| ================ | |||
| The purpose of this folder is to contain files that are auto-generated by the Projucer, | |||
| and ALL files in this folder will be mercilessly DELETED and completely re-written whenever | |||
| the Projucer saves your project. | |||
| Therefore, it's a bad idea to make any manual changes to the files in here, or to | |||
| put any of your own files in here if you don't want to lose them. (Of course you may choose | |||
| to add the folder's contents to your version-control system so that you can re-merge your own | |||
| modifications after the Projucer has saved its changes). | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_analytics/juce_analytics.cpp> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_core/juce_core.cpp> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_core/juce_core.mm> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_data_structures/juce_data_structures.cpp> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_data_structures/juce_data_structures.mm> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_events/juce_events.cpp> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_events/juce_events.mm> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_graphics/juce_graphics.cpp> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_graphics/juce_graphics.mm> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_gui_basics/juce_gui_basics.cpp> | |||
| @@ -0,0 +1,9 @@ | |||
| /* | |||
| IMPORTANT! This file is auto-generated each time you save your | |||
| project - if you alter its contents, your changes may be overwritten! | |||
| */ | |||
| #include "AppConfig.h" | |||
| #include <juce_gui_basics/juce_gui_basics.mm> | |||
| @@ -0,0 +1,217 @@ | |||
| #include "../JuceLibraryCode/JuceHeader.h" | |||
| class GoogleAnalyticsDestination : public ThreadedAnalyticsDestination | |||
| { | |||
| public: | |||
| GoogleAnalyticsDestination() | |||
| : ThreadedAnalyticsDestination ("GoogleAnalyticsThread") | |||
| { | |||
| { | |||
| // Choose where to save any unsent events. | |||
| auto appDataDir = File::getSpecialLocation (File::userApplicationDataDirectory) | |||
| .getChildFile (JUCEApplication::getInstance()->getApplicationName()); | |||
| if (! appDataDir.exists()) | |||
| appDataDir.createDirectory(); | |||
| savedEventsFile = appDataDir.getChildFile ("analytics_events.xml"); | |||
| } | |||
| { | |||
| // It's often a good idea to construct any analytics service API keys | |||
| // at runtime, so they're not searchable in the binary distribution of | |||
| // your application (but we've not done this here). You should replace | |||
| // the following key with your own to get this example application | |||
| // fully working. | |||
| apiKey = "UA-XXXXXXXXX-1"; | |||
| } | |||
| startAnalyticsThread (initialPeriodMs); | |||
| } | |||
| ~GoogleAnalyticsDestination() | |||
| { | |||
| // Here we sleep so that our background thread has a chance to send the | |||
| // last lot of batched events. Be careful - if your app takes too long to | |||
| // shut down then some operating systems will kill it forcibly! | |||
| Thread::sleep (initialPeriodMs); | |||
| stopAnalyticsThread (1000); | |||
| } | |||
| int getMaximumBatchSize() override { return 20; } | |||
| bool logBatchedEvents (const Array<AnalyticsEvent>& events) override | |||
| { | |||
| // Send events to Google Analytics. | |||
| String appData ("v=1&tid=" + apiKey + "&t=event&"); | |||
| StringArray postData; | |||
| for (auto& event : events) | |||
| { | |||
| StringPairArray data; | |||
| if (event.name == "startup") | |||
| { | |||
| data.set ("ec", "info"); | |||
| data.set ("ea", "appStarted"); | |||
| } | |||
| else if (event.name == "shutdown") | |||
| { | |||
| data.set ("ec", "info"); | |||
| data.set ("ea", "appStopped"); | |||
| } | |||
| else if (event.name == "button_press") | |||
| { | |||
| data.set ("ec", "button_press"); | |||
| data.set ("ea", event.parameters["id"]); | |||
| } | |||
| else | |||
| { | |||
| continue; | |||
| } | |||
| data.set ("cid", event.userID); | |||
| StringArray eventData; | |||
| for (auto& key : data.getAllKeys()) | |||
| eventData.add (key + "=" + URL::addEscapeChars (data[key], true)); | |||
| postData.add (appData + eventData.joinIntoString ("&")); | |||
| } | |||
| auto url = URL ("https://www.google-analytics.com/batch") | |||
| .withPOSTData (postData.joinIntoString ("\n")); | |||
| { | |||
| const ScopedLock lock (webStreamCreation); | |||
| if (shouldExit) | |||
| return false; | |||
| webStream = new WebInputStream (url, true); | |||
| } | |||
| const auto success = webStream->connect (nullptr); | |||
| // Do an exponential backoff if we failed to connect. | |||
| if (success) | |||
| periodMs = initialPeriodMs; | |||
| else | |||
| periodMs *= 2; | |||
| setBatchPeriod (periodMs); | |||
| return success; | |||
| } | |||
| void stopLoggingEvents() override | |||
| { | |||
| const ScopedLock lock (webStreamCreation); | |||
| shouldExit = true; | |||
| if (webStream != nullptr) | |||
| webStream->cancel(); | |||
| } | |||
| private: | |||
| void saveUnloggedEvents (const std::deque<AnalyticsEvent>& eventsToSave) override | |||
| { | |||
| // Save unsent events to disk. Here we use XML as a serialisation format, but | |||
| // you can use anything else as long as the restoreUnloggedEvents method can | |||
| // restore events from disk. If you're saving very large numbers of events then | |||
| // a binary format may be more suitable if it is faster - remember that this | |||
| // method is called on app shutdown so it needs to complete quickly! | |||
| XmlDocument previouslySavedEvents (savedEventsFile); | |||
| ScopedPointer<XmlElement> xml = previouslySavedEvents.getDocumentElement(); | |||
| if (xml == nullptr || xml->getTagName() != "events") | |||
| xml = new XmlElement ("events"); | |||
| for (auto& event : eventsToSave) | |||
| { | |||
| auto* xmlEvent = new XmlElement ("google_analytics_event"); | |||
| xmlEvent->setAttribute ("name", event.name); | |||
| xmlEvent->setAttribute ("timestamp", (int) event.timestamp); | |||
| xmlEvent->setAttribute ("user_id", event.userID); | |||
| auto* parameters = new XmlElement ("parameters"); | |||
| for (auto& key : event.parameters.getAllKeys()) | |||
| parameters->setAttribute (key, event.parameters[key]); | |||
| xmlEvent->addChildElement (parameters); | |||
| auto* userProperties = new XmlElement ("user_properties"); | |||
| for (auto& key : event.userProperties.getAllKeys()) | |||
| userProperties->setAttribute (key, event.userProperties[key]); | |||
| xmlEvent->addChildElement (userProperties); | |||
| xml->addChildElement (xmlEvent); | |||
| } | |||
| xml->writeToFile (savedEventsFile, {}); | |||
| } | |||
| void restoreUnloggedEvents (std::deque<AnalyticsEvent>& restoredEventQueue) override | |||
| { | |||
| XmlDocument savedEvents (savedEventsFile); | |||
| ScopedPointer<XmlElement> xml = savedEvents.getDocumentElement(); | |||
| if (xml == nullptr || xml->getTagName() != "events") | |||
| return; | |||
| const auto numEvents = xml->getNumChildElements(); | |||
| for (auto iEvent = 0; iEvent < numEvents; ++iEvent) | |||
| { | |||
| const auto* xmlEvent = xml->getChildElement (iEvent); | |||
| StringPairArray parameters; | |||
| const auto* xmlParameters = xmlEvent->getChildByName ("parameters"); | |||
| const auto numParameters = xmlParameters->getNumAttributes(); | |||
| for (auto iParam = 0; iParam < numParameters; ++iParam) | |||
| parameters.set (xmlParameters->getAttributeName (iParam), | |||
| xmlParameters->getAttributeValue (iParam)); | |||
| StringPairArray userProperties; | |||
| const auto* xmlUserProperties = xmlEvent->getChildByName ("user_properties"); | |||
| const auto numUserProperties = xmlUserProperties->getNumAttributes(); | |||
| for (auto iProp = 0; iProp < numUserProperties; ++iProp) | |||
| userProperties.set (xmlUserProperties->getAttributeName (iProp), | |||
| xmlUserProperties->getAttributeValue (iProp)); | |||
| restoredEventQueue.push_back ({ | |||
| xmlEvent->getStringAttribute ("name"), | |||
| (uint32) xmlEvent->getIntAttribute ("timestamp"), | |||
| parameters, | |||
| xmlEvent->getStringAttribute ("user_id"), | |||
| userProperties | |||
| }); | |||
| } | |||
| savedEventsFile.deleteFile(); | |||
| } | |||
| const int initialPeriodMs = 1000; | |||
| int periodMs = initialPeriodMs; | |||
| CriticalSection webStreamCreation; | |||
| bool shouldExit = false; | |||
| ScopedPointer<WebInputStream> webStream; | |||
| String apiKey; | |||
| File savedEventsFile; | |||
| }; | |||
| @@ -0,0 +1,106 @@ | |||
| #include "../JuceLibraryCode/JuceHeader.h" | |||
| #include "GoogleAnalyticsDestination.h" | |||
| #include "MainComponent.h" | |||
| //============================================================================== | |||
| class AnalyticsCollectionApplication : public JUCEApplication | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| AnalyticsCollectionApplication() {} | |||
| const String getApplicationName() override { return ProjectInfo::projectName; } | |||
| const String getApplicationVersion() override { return ProjectInfo::versionString; } | |||
| bool moreThanOneInstanceAllowed() override { return true; } | |||
| //============================================================================== | |||
| void initialise (const String&) override | |||
| { | |||
| // Add an analytics identifier for the user. Make sure you don't collect | |||
| // identifiable information accidentally if you haven't asked for permission! | |||
| Analytics::getInstance()->setUserId ("AnonUser1234"); | |||
| // Add any other constant user information. | |||
| StringPairArray userData; | |||
| userData.set ("group", "beta"); | |||
| Analytics::getInstance()->setUserProperties (userData); | |||
| // Add any analytics destinations we want to use to the Analytics singleton. | |||
| Analytics::getInstance()->addDestination (new GoogleAnalyticsDestination()); | |||
| Analytics::getInstance()->logEvent ("startup", {}); | |||
| mainWindow = new MainWindow (getApplicationName()); | |||
| } | |||
| void shutdown() override | |||
| { | |||
| Analytics::getInstance()->logEvent ("shutdown", {}); | |||
| // Add your application's shutdown code here.. | |||
| mainWindow = nullptr; // (deletes our window) | |||
| } | |||
| //============================================================================== | |||
| void systemRequestedQuit() override | |||
| { | |||
| // This is called when the app is being asked to quit: you can ignore this | |||
| // request and let the app carry on running, or call quit() to allow the app to close. | |||
| quit(); | |||
| } | |||
| void anotherInstanceStarted (const String&) override | |||
| { | |||
| // When another instance of the app is launched while this one is running, | |||
| // this method is invoked, and the commandLine parameter tells you what | |||
| // the other instance's command-line arguments were. | |||
| } | |||
| //============================================================================== | |||
| /* | |||
| This class implements the desktop window that contains an instance of | |||
| our MainContentComponent class. | |||
| */ | |||
| class MainWindow : public DocumentWindow | |||
| { | |||
| public: | |||
| MainWindow (String name) : DocumentWindow (name, | |||
| Desktop::getInstance().getDefaultLookAndFeel() | |||
| .findColour (ResizableWindow::backgroundColourId), | |||
| DocumentWindow::allButtons) | |||
| { | |||
| setUsingNativeTitleBar (true); | |||
| setContentOwned (new MainContentComponent(), true); | |||
| centreWithSize (getWidth(), getHeight()); | |||
| setVisible (true); | |||
| } | |||
| void closeButtonPressed() override | |||
| { | |||
| // This is called when the user tries to close this window. Here, we'll just | |||
| // ask the app to quit when this happens, but you can change this to do | |||
| // whatever you need. | |||
| JUCEApplication::getInstance()->systemRequestedQuit(); | |||
| } | |||
| /* Note: Be careful if you override any DocumentWindow methods - the base | |||
| class uses a lot of them, so by overriding you might break its functionality. | |||
| It's best to do all your work in your content component instead, but if | |||
| you really have to override any DocumentWindow methods, make sure your | |||
| subclass also calls the superclass's method. | |||
| */ | |||
| private: | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) | |||
| }; | |||
| private: | |||
| ScopedPointer<MainWindow> mainWindow; | |||
| }; | |||
| //============================================================================== | |||
| // This macro generates the main() routine that launches the app. | |||
| START_JUCE_APPLICATION (AnalyticsCollectionApplication) | |||
| @@ -0,0 +1,38 @@ | |||
| #pragma once | |||
| #include "../JuceLibraryCode/JuceHeader.h" | |||
| class MainContentComponent : public Component | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| MainContentComponent() | |||
| { | |||
| addAndMakeVisible (eventButton); | |||
| setSize (300, 200); | |||
| StringPairArray logButtonPressParameters; | |||
| logButtonPressParameters.set ("id", "a"); | |||
| logEventButtonPress = new ButtonTracker (eventButton, "button_press", logButtonPressParameters); | |||
| } | |||
| ~MainContentComponent() {} | |||
| void paint (Graphics& g) override | |||
| { | |||
| g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId)); | |||
| } | |||
| void resized() override | |||
| { | |||
| eventButton.centreWithSize (100, 50); | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| TextButton eventButton { "Press me!" }; | |||
| ScopedPointer<ButtonTracker> logEventButtonPress; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent) | |||
| }; | |||
| @@ -39,6 +39,7 @@ | |||
| <MODULEPATH id="juce_audio_utils" path="../../modules"/> | |||
| <MODULEPATH id="juce_blocks_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_product_unlocking" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </XCODE_MAC> | |||
| <LINUX_MAKE targetFolder="Builds/LinuxMakefile"> | |||
| @@ -67,6 +68,7 @@ | |||
| <MODULEPATH id="juce_audio_utils" path="../../modules"/> | |||
| <MODULEPATH id="juce_blocks_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_product_unlocking" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </LINUX_MAKE> | |||
| <VS2017 targetFolder="Builds/VisualStudio2017"> | |||
| @@ -97,10 +99,12 @@ | |||
| <MODULEPATH id="juce_audio_formats" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_devices" path="../../modules"/> | |||
| <MODULEPATH id="juce_audio_basics" path="../../modules"/> | |||
| <MODULEPATH id="juce_analytics" path="../../modules"/> | |||
| </MODULEPATHS> | |||
| </VS2017> | |||
| </EXPORTFORMATS> | |||
| <MODULES> | |||
| <MODULE id="juce_analytics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/> | |||
| <MODULES id="juce_audio_basics" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_audio_devices" showAllCode="1" useLocalCopy="0"/> | |||
| <MODULES id="juce_audio_formats" showAllCode="1" useLocalCopy="0"/> | |||
| @@ -0,0 +1,67 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| void Analytics::addDestination (AnalyticsDestination* destination) | |||
| { | |||
| destinations.add (destination); | |||
| } | |||
| void Analytics::setUserId (const String& newUserId) | |||
| { | |||
| userId = newUserId; | |||
| } | |||
| void Analytics::setUserProperties (const StringPairArray& properties) | |||
| { | |||
| userProperties = properties; | |||
| } | |||
| void Analytics::logEvent (const String& eventName, | |||
| const StringPairArray& parameters) | |||
| { | |||
| if (! isSuspended) | |||
| { | |||
| AnalyticsDestination::AnalyticsEvent event | |||
| { | |||
| eventName, | |||
| Time::getMillisecondCounter(), | |||
| parameters, | |||
| userId, | |||
| userProperties | |||
| }; | |||
| for (auto* destination : destinations) | |||
| destination->logEvent (event); | |||
| } | |||
| } | |||
| void Analytics::setSuspended (bool shouldBeSuspended) | |||
| { | |||
| isSuspended = shouldBeSuspended; | |||
| } | |||
| juce_ImplementSingleton (Analytics) | |||
| } | |||
| @@ -0,0 +1,99 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| //============================================================================== | |||
| /** | |||
| A singleton class to manage analytics data. | |||
| Use an Analytics object to manage sending analytics data to one or more | |||
| AnalyticsDestinations. | |||
| @see AnalyticsDestination, ThreadedAnalyticsDestination, | |||
| AnalyticsDestination::AnalyticsEvent | |||
| */ | |||
| class JUCE_API Analytics : public DeletedAtShutdown | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Adds an AnalyticsDestination to the list of AnalyticsDestinations | |||
| managed by this Analytics object. | |||
| The Analytics class will take ownership of the AnalyticsDestination | |||
| passed to this function. | |||
| @param destination the AnalyticsDestination to manage | |||
| */ | |||
| void addDestination (AnalyticsDestination* destination); | |||
| /** Sets a user ID that will be added to all AnalyticsEvents sent to | |||
| AnalyticsDestinations. | |||
| @param newUserId the userId to add to AnalyticsEvents | |||
| */ | |||
| void setUserId (const String& newUserId); | |||
| /** Sets some user properties that will be added to all AnalyticsEvents sent | |||
| to AnalyticsDestinations. | |||
| @param properties the userProperties to add to AnalyticsEvents | |||
| */ | |||
| void setUserProperties (const StringPairArray& properties); | |||
| /** Sends an AnalyticsEvent to all AnalyticsDestinations. | |||
| The AnalyticsEvent will be timestamped, and will have the userId and | |||
| userProperties populated by values previously set by calls to | |||
| setUserId and setUserProperties. The name and parameters will be | |||
| populated by the arguments supplied to this function. | |||
| @param eventName the event name | |||
| @param parameters the event parameters | |||
| */ | |||
| void logEvent (const String& eventName, const StringPairArray& parameters); | |||
| /** Suspends analytics submission to AnalyticsDestinations. | |||
| @param shouldBeSuspended if event submission should be suspended | |||
| */ | |||
| void setSuspended (bool shouldBeSuspended); | |||
| juce_DeclareSingleton (Analytics, true) | |||
| private: | |||
| //============================================================================== | |||
| Analytics() = default; | |||
| String userId; | |||
| StringPairArray userProperties; | |||
| bool isSuspended = false; | |||
| OwnedArray<AnalyticsDestination> destinations; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Analytics) | |||
| }; | |||
| } // namespace juce | |||
| @@ -0,0 +1,55 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| ButtonTracker::ButtonTracker (Button& buttonToTrack, | |||
| const String& triggeredEventName, | |||
| const StringPairArray& triggeredEventParameters) | |||
| : button (buttonToTrack), | |||
| eventName (triggeredEventName), | |||
| eventParameters (triggeredEventParameters) | |||
| { | |||
| button.addListener (this); | |||
| } | |||
| ButtonTracker::~ButtonTracker() | |||
| { | |||
| button.removeListener (this); | |||
| } | |||
| void ButtonTracker::buttonClicked (Button* b) | |||
| { | |||
| if (b == &button) | |||
| { | |||
| auto params = eventParameters; | |||
| if (button.getClickingTogglesState()) | |||
| params.set ("ButtonState", button.getToggleState() ? "On" : "Off"); | |||
| Analytics::getInstance()->logEvent (eventName, params); | |||
| } | |||
| } | |||
| } // namespace juce | |||
| @@ -0,0 +1,70 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| //============================================================================== | |||
| /** | |||
| A class that automatically sends analytics events to the Analytics singleton | |||
| when a button is clicked. | |||
| @see Analytics, AnalyticsDestination::AnalyticsEvent | |||
| */ | |||
| class JUCE_API ButtonTracker : private Button::Listener | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** | |||
| Creating one of these automatically sends analytics events to the Analytics | |||
| singeton when the corresponding button is clicked. | |||
| The name and parameters of the analytics event will be populated from the | |||
| variables supplied here. If clicking changes the button's state then the | |||
| parameters will have a {"ButtonState", "On"/"Off"} entry added. | |||
| @param buttonToTrack the button to track | |||
| @param triggeredEventName the name of the generated event | |||
| @param triggeredEventParameters the parameters to add to the generated | |||
| event | |||
| @see Analytics, AnalyticsDestination::AnalyticsEvent | |||
| */ | |||
| ButtonTracker (Button& buttonToTrack, | |||
| const String& triggeredEventName, | |||
| const StringPairArray& triggeredEventParameters = {}); | |||
| /** Destructor. */ | |||
| ~ButtonTracker(); | |||
| private: | |||
| /** @internal */ | |||
| void buttonClicked (Button*) override; | |||
| Button& button; | |||
| const String eventName; | |||
| const StringPairArray eventParameters; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonTracker) | |||
| }; | |||
| } // namespace juce | |||
| @@ -0,0 +1,86 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| //============================================================================== | |||
| /** | |||
| An interface for handling analytics events collected by an Analytics object. | |||
| For basic analytics logging you can implement this interface and add your | |||
| class to an Analytics object. | |||
| For more advanced logging you may want to subclass | |||
| ThreadedAnalyticsDestination instead, which is more suitable for interacting | |||
| with web servers and other time consuming destinations. | |||
| @see Analytics, ThreadedAnalyticsDestination | |||
| */ | |||
| struct JUCE_API AnalyticsDestination | |||
| { | |||
| /** Contains information about an event to be logged. */ | |||
| struct AnalyticsEvent | |||
| { | |||
| /** The name of the event. */ | |||
| String name; | |||
| /** | |||
| The timestamp of the event. | |||
| Timestamps are automatically applied by an Analytics object and are | |||
| derived from Time::getMillisecondCounter(). As such these timestamps | |||
| do not represent absolute times, but relative timings of events for | |||
| each user in each session will be accurate. | |||
| */ | |||
| uint32 timestamp; | |||
| /** The parameters of the event. */ | |||
| StringPairArray parameters; | |||
| /** The user ID associated with the event. */ | |||
| String userID; | |||
| /** Properties associated with the user. */ | |||
| StringPairArray userProperties; | |||
| }; | |||
| /** Constructor. */ | |||
| AnalyticsDestination() = default; | |||
| /** Destructor. */ | |||
| virtual ~AnalyticsDestination() {} | |||
| /** | |||
| When an AnalyticsDestination is added to an Analytics object this method | |||
| is called when an analytics event is triggered from the Analytics | |||
| object. | |||
| Override this method to log the event information somewhere useful. | |||
| */ | |||
| virtual void logEvent (const AnalyticsEvent& event) = 0; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnalyticsDestination) | |||
| }; | |||
| } // namespace juce | |||
| @@ -0,0 +1,350 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| ThreadedAnalyticsDestination::ThreadedAnalyticsDestination (const String& threadName) | |||
| : dispatcher (threadName, *this) | |||
| {} | |||
| ThreadedAnalyticsDestination::~ThreadedAnalyticsDestination() | |||
| { | |||
| // If you hit this assertion then the analytics thread has not been shut down | |||
| // before this class is destroyed. Call stopAnalyticsThread() in your destructor! | |||
| jassert (! dispatcher.isThreadRunning()); | |||
| } | |||
| void ThreadedAnalyticsDestination::setBatchPeriod (int newBatchPeriodMilliseconds) | |||
| { | |||
| dispatcher.batchPeriodMilliseconds = newBatchPeriodMilliseconds; | |||
| } | |||
| void ThreadedAnalyticsDestination::logEvent (const AnalyticsEvent& event) | |||
| { | |||
| dispatcher.addToQueue (event); | |||
| } | |||
| void ThreadedAnalyticsDestination::startAnalyticsThread (int initialBatchPeriodMilliseconds) | |||
| { | |||
| setBatchPeriod (initialBatchPeriodMilliseconds); | |||
| dispatcher.startThread(); | |||
| } | |||
| void ThreadedAnalyticsDestination::stopAnalyticsThread (int timeout) | |||
| { | |||
| dispatcher.signalThreadShouldExit(); | |||
| stopLoggingEvents(); | |||
| dispatcher.stopThread (timeout); | |||
| if (dispatcher.eventQueue.size() > 0) | |||
| saveUnloggedEvents (dispatcher.eventQueue); | |||
| } | |||
| ThreadedAnalyticsDestination::EventDispatcher::EventDispatcher (const String& threadName, | |||
| ThreadedAnalyticsDestination& destination) | |||
| : Thread (threadName), | |||
| parent (destination) | |||
| {} | |||
| void ThreadedAnalyticsDestination::EventDispatcher::run() | |||
| { | |||
| // We may have inserted some events into the queue (on the message thread) | |||
| // before this thread has started, so make sure the old events are at the | |||
| // front of the queue. | |||
| { | |||
| std::deque<AnalyticsEvent> restoredEventQueue; | |||
| parent.restoreUnloggedEvents (restoredEventQueue); | |||
| const ScopedLock lock (queueAccess); | |||
| for (auto rit = restoredEventQueue.rbegin(); rit != restoredEventQueue.rend(); ++rit) | |||
| eventQueue.push_front (*rit); | |||
| } | |||
| const int maxBatchSize = parent.getMaximumBatchSize(); | |||
| while (! threadShouldExit()) | |||
| { | |||
| auto eventsToSendCapacity = maxBatchSize - eventsToSend.size(); | |||
| if (eventsToSendCapacity > 0) | |||
| { | |||
| const ScopedLock lock (queueAccess); | |||
| const auto numEventsInQueue = (int) eventQueue.size(); | |||
| if (numEventsInQueue > 0) | |||
| { | |||
| const auto numEventsToAdd = jmin (eventsToSendCapacity, numEventsInQueue); | |||
| for (size_t i = 0; i < (size_t) numEventsToAdd; ++i) | |||
| eventsToSend.add (eventQueue[i]); | |||
| } | |||
| } | |||
| const auto submissionTime = Time::getMillisecondCounter(); | |||
| if (! eventsToSend.isEmpty()) | |||
| { | |||
| if (parent.logBatchedEvents (eventsToSend)) | |||
| { | |||
| const ScopedLock lock (queueAccess); | |||
| for (auto i = 0; i < eventsToSend.size(); ++i) | |||
| eventQueue.pop_front(); | |||
| eventsToSend.clearQuick(); | |||
| } | |||
| } | |||
| while (Time::getMillisecondCounter() - submissionTime < (uint32) batchPeriodMilliseconds.get()) | |||
| { | |||
| if (threadShouldExit()) | |||
| return; | |||
| Thread::sleep (100); | |||
| } | |||
| } | |||
| } | |||
| void ThreadedAnalyticsDestination::EventDispatcher::addToQueue (const AnalyticsEvent& event) | |||
| { | |||
| const ScopedLock lock (queueAccess); | |||
| eventQueue.push_back (event); | |||
| } | |||
| //============================================================================== | |||
| #if JUCE_UNIT_TESTS | |||
| namespace DestinationTestHelpers | |||
| { | |||
| //============================================================================== | |||
| struct TestDestination : public ThreadedAnalyticsDestination | |||
| { | |||
| TestDestination (std::deque<AnalyticsEvent>& loggedEvents, | |||
| std::deque<AnalyticsEvent>& unloggedEvents) | |||
| : ThreadedAnalyticsDestination ("ThreadedAnalyticsDestinationTest"), | |||
| loggedEventQueue (loggedEvents), | |||
| unloggedEventStore (unloggedEvents) | |||
| {} | |||
| virtual ~TestDestination() {} | |||
| int getMaximumBatchSize() override | |||
| { | |||
| return 5; | |||
| } | |||
| void saveUnloggedEvents (const std::deque<AnalyticsEvent>& eventsToSave) override | |||
| { | |||
| unloggedEventStore = eventsToSave; | |||
| } | |||
| void restoreUnloggedEvents (std::deque<AnalyticsEvent>& restoredEventQueue) override | |||
| { | |||
| restoredEventQueue = unloggedEventStore; | |||
| } | |||
| std::deque<AnalyticsEvent>& loggedEventQueue; | |||
| std::deque<AnalyticsEvent>& unloggedEventStore; | |||
| }; | |||
| //============================================================================== | |||
| struct BasicDestination : public TestDestination | |||
| { | |||
| BasicDestination (std::deque<AnalyticsEvent>& loggedEvents, | |||
| std::deque<AnalyticsEvent>& unloggedEvents) | |||
| : TestDestination (loggedEvents, unloggedEvents) | |||
| { | |||
| startAnalyticsThread (100); | |||
| } | |||
| virtual ~BasicDestination() | |||
| { | |||
| stopAnalyticsThread (1000); | |||
| } | |||
| bool logBatchedEvents (const Array<AnalyticsEvent>& events) override | |||
| { | |||
| jassert (events.size() <= getMaximumBatchSize()); | |||
| for (auto& event : events) | |||
| loggedEventQueue.push_back (event); | |||
| return true; | |||
| } | |||
| void stopLoggingEvents() override {} | |||
| }; | |||
| //============================================================================== | |||
| struct SlowWebDestination : public TestDestination | |||
| { | |||
| SlowWebDestination (std::deque<AnalyticsEvent>& loggedEvents, | |||
| std::deque<AnalyticsEvent>& unloggedEvents) | |||
| : TestDestination (loggedEvents, unloggedEvents) | |||
| { | |||
| startAnalyticsThread (initialPeriod); | |||
| } | |||
| virtual ~SlowWebDestination() | |||
| { | |||
| stopAnalyticsThread (1000); | |||
| } | |||
| bool logBatchedEvents (const Array<AnalyticsEvent>& events) override | |||
| { | |||
| threadHasStarted.signal(); | |||
| jassert (events.size() <= getMaximumBatchSize()); | |||
| { | |||
| const ScopedLock lock (webStreamCreation); | |||
| if (shouldExit) | |||
| return false; | |||
| // An attempt to connect to an unroutable IP address will hang | |||
| // indefinitely, which simulates a very slow server | |||
| webStream = new WebInputStream (URL ("http://1.192.0.0"), true); | |||
| } | |||
| String data; | |||
| for (auto& event : events) | |||
| data << event.name; | |||
| webStream->withExtraHeaders (data); | |||
| const auto success = webStream->connect (nullptr); | |||
| // Exponential backoff on failure | |||
| if (success) | |||
| period = initialPeriod; | |||
| else | |||
| period *= 2; | |||
| setBatchPeriod (period); | |||
| return success; | |||
| } | |||
| void stopLoggingEvents() override | |||
| { | |||
| const ScopedLock lock (webStreamCreation); | |||
| shouldExit = true; | |||
| if (webStream != nullptr) | |||
| webStream->cancel(); | |||
| } | |||
| const int initialPeriod = 100; | |||
| int period = initialPeriod; | |||
| CriticalSection webStreamCreation; | |||
| bool shouldExit = false; | |||
| ScopedPointer<WebInputStream> webStream; | |||
| WaitableEvent threadHasStarted; | |||
| }; | |||
| } | |||
| //============================================================================== | |||
| struct ThreadedAnalyticsDestinationTests : public UnitTest | |||
| { | |||
| ThreadedAnalyticsDestinationTests() | |||
| : UnitTest ("ThreadedAnalyticsDestination") | |||
| {} | |||
| void compareEventQueues (const std::deque<AnalyticsDestination::AnalyticsEvent>& a, | |||
| const std::deque<AnalyticsDestination::AnalyticsEvent>& b) | |||
| { | |||
| const auto numEntries = a.size(); | |||
| expectEquals (b.size(), numEntries); | |||
| for (size_t i = 0; i < numEntries; ++i) | |||
| { | |||
| expectEquals (a[i].name, b[i].name); | |||
| expect (a[i].timestamp == b[i].timestamp); | |||
| } | |||
| } | |||
| void runTest() override | |||
| { | |||
| std::deque<AnalyticsDestination::AnalyticsEvent> testEvents; | |||
| for (int i = 0; i < 7; ++i) | |||
| testEvents.push_back ({ String (i), Time::getMillisecondCounter(), {}, "TestUser", {} }); | |||
| std::deque<AnalyticsDestination::AnalyticsEvent> loggedEvents, unloggedEvents; | |||
| beginTest ("Basic"); | |||
| { | |||
| DestinationTestHelpers::BasicDestination destination (loggedEvents, unloggedEvents); | |||
| for (auto& event : testEvents) | |||
| destination.logEvent (event); | |||
| Thread::sleep (400); | |||
| compareEventQueues (loggedEvents, testEvents); | |||
| expect (unloggedEvents.size() == 0); | |||
| loggedEvents.clear(); | |||
| } | |||
| beginTest ("Web"); | |||
| { | |||
| { | |||
| DestinationTestHelpers::SlowWebDestination destination (loggedEvents, unloggedEvents); | |||
| for (auto& event : testEvents) | |||
| destination.logEvent (event); | |||
| } | |||
| expect (loggedEvents.size() == 0); | |||
| compareEventQueues (unloggedEvents, testEvents); | |||
| { | |||
| DestinationTestHelpers::SlowWebDestination destination (loggedEvents, unloggedEvents); | |||
| destination.threadHasStarted.wait(); | |||
| unloggedEvents.clear(); | |||
| } | |||
| expect (loggedEvents.size() == 0); | |||
| compareEventQueues (unloggedEvents, testEvents); | |||
| unloggedEvents.clear(); | |||
| } | |||
| } | |||
| }; | |||
| static ThreadedAnalyticsDestinationTests threadedAnalyticsDestinationTests; | |||
| #endif | |||
| } // namespace juce | |||
| @@ -0,0 +1,212 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| //============================================================================== | |||
| /** | |||
| A base class for dispatching analytics events on a dedicated thread. | |||
| This class is particularly useful for sending analytics events to a web | |||
| server without blocking the message thread. It can also save (and restore) | |||
| events that were not dispatched so no information is lost when an internet | |||
| connection is absent or something else prevents successful logging. | |||
| Once startAnalyticsThread is called the logBatchedEvents method is | |||
| periodically invoked on an analytics thread, with the period determined by | |||
| calls to setBatchPeriod. Here events are grouped together into batches, with | |||
| the maximum batch size set by the implementation of getMaximumBatchSize. | |||
| It's important to call stopAnalyticsThread in the destructor of your | |||
| subclass (or before then) to give the analytics thread time to shut down. | |||
| Calling stopAnalyticsThread will, in turn, call stopLoggingEvents, which | |||
| you should use to terminate the currently running logBatchedEvents call. | |||
| @see Analytics, AnalyticsDestination, AnalyticsDestination::AnalyticsEvent | |||
| */ | |||
| class JUCE_API ThreadedAnalyticsDestination : public AnalyticsDestination | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** | |||
| Creates a ThreadedAnalyticsDestination. | |||
| @param threadName used to identify the analytics | |||
| thread in debug builds | |||
| */ | |||
| ThreadedAnalyticsDestination (const String& threadName = "Analytics thread"); | |||
| /** Destructor. */ | |||
| virtual ~ThreadedAnalyticsDestination(); | |||
| //============================================================================== | |||
| /** | |||
| Override this method to provide the maximum batch size you can handle in | |||
| your subclass. | |||
| Calls to logBatchedEvents will contain no more than this number of events. | |||
| */ | |||
| virtual int getMaximumBatchSize() = 0; | |||
| /** | |||
| This method will be called periodically on the analytics thread. | |||
| If this method returns false then the subsequent call of this function will | |||
| contain the same events as previous call, plus any new events that have been | |||
| generated in the period between calls. The order of events will not be | |||
| changed. This allows you to retry logging events until they are logged | |||
| successfully. | |||
| @param events a list of events to be logged | |||
| @returns if the events were successfully logged | |||
| */ | |||
| virtual bool logBatchedEvents (const Array<AnalyticsEvent>& events) = 0; | |||
| /** | |||
| You must always call stopAnalyticsThread in the destructor of your subclass | |||
| (or before then) to give the analytics thread time to shut down. | |||
| Calling stopAnalyticsThread triggers a call to this method. At this point | |||
| you are guaranteed that logBatchedEvents has been called for the last time | |||
| and you should make sure that the current call to logBatchedEvents finishes | |||
| as quickly as possible. This method and a subsequent call to | |||
| saveUnloggedEvents must both complete before the timeout supplied to | |||
| stopAnalyticsThread. | |||
| In a normal use case stopLoggingEvents will be called on the message thread | |||
| from the destructor of your ThreadedAnalyticsDestination subclass, and must | |||
| stop the logBatchedEvents method which is running on the analytics thread. | |||
| @see stopAnalyticsThread | |||
| */ | |||
| virtual void stopLoggingEvents() = 0; | |||
| //============================================================================== | |||
| /** | |||
| Call this to set the period between logBatchedEvents invocations. | |||
| This method is thread safe and can be used to implements things like | |||
| exponential backoff in logBatchedEvents calls. | |||
| @param newSubmissionPeriodMilliseconds the new submission period to | |||
| use in milliseconds | |||
| */ | |||
| void setBatchPeriod (int newSubmissionPeriodMilliseconds); | |||
| /** | |||
| Adds an event to the queue, which will ultimately be submitted to | |||
| logBatchedEvents. | |||
| This method is thread safe. | |||
| @param event the analytics event to add to the queue | |||
| */ | |||
| void logEvent (const AnalyticsEvent& event) override final; | |||
| protected: | |||
| //============================================================================== | |||
| /** | |||
| Starts the analytics thread, with an initial event batching period. | |||
| @param initialBatchPeriodMilliseconds the initial event batching period | |||
| in milliseconds | |||
| */ | |||
| void startAnalyticsThread (int initialBatchPeriodMilliseconds); | |||
| //============================================================================== | |||
| /** | |||
| Triggers the shutdown of the analytics thread. | |||
| You must call this method in the destructor of your subclass (or before | |||
| then) to give the analytics thread time to shut down. | |||
| This method invokes stopLoggingEvents and you should ensure that both the | |||
| analytics thread and a call to saveUnloggedEvents are able to finish before | |||
| the supplied timeout. This timeout is important because on platforms like | |||
| iOS an app is killed if it takes too long to shut down. | |||
| @param timeoutMilliseconds the number of milliseconds before | |||
| the analytics thread is forcibly | |||
| terminated | |||
| */ | |||
| void stopAnalyticsThread (int timeoutMilliseconds); | |||
| private: | |||
| //============================================================================== | |||
| /** | |||
| This method will be called when the analytics thread is shut down, | |||
| giving you the chance to save any analytics events that could not be | |||
| logged. Once saved these events can be put back into the queue of events | |||
| when the ThreadedAnalyticsDestination is recreated via | |||
| restoreUnloggedEvents. | |||
| This method should return as quickly as possible, as both | |||
| stopLoggingEvents and this method need to complete inside the timeout | |||
| set in stopAnalyticsThread. | |||
| @param eventsToSave the events that could not be logged | |||
| @see stopAnalyticsThread, stopLoggingEvents, restoreUnloggedEvents | |||
| */ | |||
| virtual void saveUnloggedEvents (const std::deque<AnalyticsEvent>& eventsToSave) = 0; | |||
| /** | |||
| The counterpart to saveUnloggedEvents. | |||
| Events added to the event queue provided by this method will be the | |||
| first events supplied to logBatchedEvents calls. Use this method to | |||
| restore any unlogged events previously stored in a call to | |||
| saveUnloggedEvents. | |||
| This method is called on the analytics thread. | |||
| @param restoredEventQueue place restored events into this queue | |||
| @see saveUnloggedEvents | |||
| */ | |||
| virtual void restoreUnloggedEvents (std::deque<AnalyticsEvent>& restoredEventQueue) = 0; | |||
| struct EventDispatcher : public Thread | |||
| { | |||
| EventDispatcher (const String& threadName, ThreadedAnalyticsDestination&); | |||
| void run() override; | |||
| void addToQueue (const AnalyticsEvent&); | |||
| ThreadedAnalyticsDestination& parent; | |||
| std::deque<AnalyticsEvent> eventQueue; | |||
| CriticalSection queueAccess; | |||
| Atomic<int> batchPeriodMilliseconds { 1000 }; | |||
| Array<AnalyticsEvent> eventsToSend; | |||
| }; | |||
| const String destinationName; | |||
| EventDispatcher dispatcher; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadedAnalyticsDestination) | |||
| }; | |||
| } // namespace juce | |||
| @@ -0,0 +1,40 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| #ifdef JUCE_ANALYTICS_H_INCLUDED | |||
| /* When you add this cpp file to your project, you mustn't include it in a file where you've | |||
| already included any other headers - just put it inside a file on its own, possibly with your config | |||
| flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix | |||
| header files that the compiler may be using. | |||
| */ | |||
| #error "Incorrect use of JUCE cpp file" | |||
| #endif | |||
| #include "juce_analytics.h" | |||
| #include "destinations/juce_ThreadedAnalyticsDestination.cpp" | |||
| #include "analytics/juce_Analytics.cpp" | |||
| #include "analytics/juce_ButtonTracker.cpp" | |||
| @@ -0,0 +1,56 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| The code included in this file is provided under the terms of the ISC license | |||
| http://www.isc.org/downloads/software-support-policy/isc-license. Permission | |||
| To use, copy, modify, and/or distribute this software for any purpose with or | |||
| without fee is hereby granted provided that the above copyright notice and | |||
| this permission notice appear in all copies. | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| /******************************************************************************* | |||
| The block below describes the properties of this module, and is read by | |||
| the Projucer to automatically generate project code that uses it. | |||
| For details about the syntax and how to create or use a module, see the | |||
| JUCE Module Format.txt file. | |||
| BEGIN_JUCE_MODULE_DECLARATION | |||
| ID: juce_analytics | |||
| vendor: juce | |||
| version: 5.1.1 | |||
| name: JUCE analytics classes | |||
| description: Classes to collect analytics and send to destinations | |||
| website: http://www.juce.com/juce | |||
| license: GPL/Commercial | |||
| dependencies: juce_gui_basics | |||
| END_JUCE_MODULE_DECLARATION | |||
| *******************************************************************************/ | |||
| #pragma once | |||
| #define JUCE_ANALYTICS_H_INCLUDED | |||
| #include <queue> | |||
| #include <juce_gui_basics/juce_gui_basics.h> | |||
| #include "destinations/juce_AnalyticsDestination.h" | |||
| #include "destinations/juce_ThreadedAnalyticsDestination.h" | |||
| #include "analytics/juce_Analytics.h" | |||
| #include "analytics/juce_ButtonTracker.h" | |||