diff --git a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/android/vending/billing/IInAppBillingService.java b/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/android/vending/billing/IInAppBillingService.java deleted file mode 100644 index a40a251ebc..0000000000 --- a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/android/vending/billing/IInAppBillingService.java +++ /dev/null @@ -1,949 +0,0 @@ -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 _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 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 - 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 containing the list of SKUs - * "INAPP_PURCHASE_DATA_LIST" - ArrayList containing the purchase information - * "INAPP_DATA_SIGNATURE_LIST"- ArrayList 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 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 - 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 containing the list of SKUs - * "INAPP_PURCHASE_DATA_LIST" - ArrayList containing the purchase information - * "INAPP_DATA_SIGNATURE_LIST"- ArrayList 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; - } diff --git a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java b/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java deleted file mode 100644 index 61c6f68970..0000000000 --- a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java +++ /dev/null @@ -1,3170 +0,0 @@ -/* - ============================================================================== - - 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. - - ============================================================================== -*/ - -package com.juce.audioperformancetest; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.hardware.camera2.*; -import android.database.ContentObserver; -import android.media.session.*; -import android.media.MediaMetadata; -import android.net.http.SslError; -import android.net.Uri; -import android.os.Bundle; -import android.os.Looper; -import android.os.Handler; -import android.os.Message; -import android.os.ParcelUuid; -import android.os.Environment; -import android.view.*; -import android.view.inputmethod.BaseInputConnection; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodManager; -import android.graphics.*; -import android.text.ClipboardManager; -import android.text.InputType; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.Pair; -import android.webkit.SslErrorHandler; -import android.webkit.WebChromeClient; -import android.webkit.WebResourceError; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import java.lang.Runnable; -import java.lang.ref.WeakReference; -import java.lang.reflect.*; -import java.util.*; -import java.io.*; -import java.net.URL; -import java.net.HttpURLConnection; -import android.media.AudioManager; -import android.Manifest; -import java.util.concurrent.CancellationException; -import java.util.concurrent.Future; -import java.util.concurrent.Executors; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.atomic.*; - -import android.media.midi.*; -import android.bluetooth.*; -import android.bluetooth.le.*; - - -//============================================================================== -public class AudioPerformanceTest extends Activity -{ - //============================================================================== - static - { - System.loadLibrary ("juce_jni"); - } - - //============================================================================== - public boolean isPermissionDeclaredInManifest (int permissionID) - { - return isPermissionDeclaredInManifest (getAndroidPermissionName (permissionID)); - } - - public boolean isPermissionDeclaredInManifest (String permissionToCheck) - { - try - { - PackageInfo info = getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS); - - if (info.requestedPermissions != null) - for (String permission : info.requestedPermissions) - if (permission.equals (permissionToCheck)) - return true; - } - catch (PackageManager.NameNotFoundException e) - { - Log.d ("JUCE", "isPermissionDeclaredInManifest: PackageManager.NameNotFoundException = " + e.toString()); - } - - Log.d ("JUCE", "isPermissionDeclaredInManifest: could not find requested permission " + permissionToCheck); - return false; - } - - //============================================================================== - // these have to match the values of enum PermissionID in C++ class RuntimePermissions: - private static final int JUCE_PERMISSIONS_RECORD_AUDIO = 1; - private static final int JUCE_PERMISSIONS_BLUETOOTH_MIDI = 2; - private static final int JUCE_PERMISSIONS_READ_EXTERNAL_STORAGE = 3; - private static final int JUCE_PERMISSIONS_WRITE_EXTERNAL_STORAGE = 4; - private static final int JUCE_PERMISSIONS_CAMERA = 5; - - private static String getAndroidPermissionName (int permissionID) - { - switch (permissionID) - { - case JUCE_PERMISSIONS_RECORD_AUDIO: return Manifest.permission.RECORD_AUDIO; - case JUCE_PERMISSIONS_BLUETOOTH_MIDI: return Manifest.permission.ACCESS_COARSE_LOCATION; - // use string value as this is not defined in SDKs < 16 - case JUCE_PERMISSIONS_READ_EXTERNAL_STORAGE: return "android.permission.READ_EXTERNAL_STORAGE"; - case JUCE_PERMISSIONS_WRITE_EXTERNAL_STORAGE: return Manifest.permission.WRITE_EXTERNAL_STORAGE; - case JUCE_PERMISSIONS_CAMERA: return Manifest.permission.CAMERA; - } - - // unknown permission ID! - assert false; - return new String(); - } - - public boolean isPermissionGranted (int permissionID) - { - return getApplicationContext().checkCallingOrSelfPermission (getAndroidPermissionName (permissionID)) == PackageManager.PERMISSION_GRANTED; - } - - private Map permissionCallbackPtrMap; - - public void requestRuntimePermission (int permissionID, long ptrToCallback) - { - String permissionName = getAndroidPermissionName (permissionID); - - if (getApplicationContext().checkCallingOrSelfPermission (permissionName) != PackageManager.PERMISSION_GRANTED) - { - // remember callbackPtr, request permissions, and let onRequestPermissionResult call callback asynchronously - permissionCallbackPtrMap.put (permissionID, ptrToCallback); - requestPermissionsCompat (new String[]{permissionName}, permissionID); - } - else - { - // permissions were already granted before, we can call callback directly - androidRuntimePermissionsCallback (true, ptrToCallback); - } - } - - private native void androidRuntimePermissionsCallback (boolean permissionWasGranted, long ptrToCallback); - - @Override - public void onRequestPermissionsResult (int permissionID, String permissions[], int[] grantResults) - { - boolean permissionsGranted = (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED); - - if (! permissionsGranted) - Log.d ("JUCE", "onRequestPermissionsResult: runtime permission was DENIED: " + getAndroidPermissionName (permissionID)); - - Long ptrToCallback = permissionCallbackPtrMap.get (permissionID); - permissionCallbackPtrMap.remove (permissionID); - androidRuntimePermissionsCallback (permissionsGranted, ptrToCallback); - } - - //============================================================================== - public interface JuceMidiPort - { - boolean isInputPort(); - - // start, stop does nothing on an output port - void start(); - void stop(); - - void close(); - - // send will do nothing on an input port - void sendMidi (byte[] msg, int offset, int count); - } - - //============================================================================== - //============================================================================== - public class BluetoothManager extends ScanCallback - { - BluetoothManager() - { - } - - public String[] getMidiBluetoothAddresses() - { - return bluetoothMidiDevices.toArray (new String[bluetoothMidiDevices.size()]); - } - - public String getHumanReadableStringForBluetoothAddress (String address) - { - BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address); - return btDevice.getName(); - } - - public int getBluetoothDeviceStatus (String address) - { - return getAndroidMidiDeviceManager().getBluetoothDeviceStatus (address); - } - - public void startStopScan (boolean shouldStart) - { - BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - - if (bluetoothAdapter == null) - { - Log.d ("JUCE", "BluetoothManager error: could not get default Bluetooth adapter"); - return; - } - - BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); - - if (bluetoothLeScanner == null) - { - Log.d ("JUCE", "BluetoothManager error: could not get Bluetooth LE scanner"); - return; - } - - if (shouldStart) - { - ScanFilter.Builder scanFilterBuilder = new ScanFilter.Builder(); - scanFilterBuilder.setServiceUuid (ParcelUuid.fromString (bluetoothLEMidiServiceUUID)); - - ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder(); - scanSettingsBuilder.setCallbackType (ScanSettings.CALLBACK_TYPE_ALL_MATCHES) - .setScanMode (ScanSettings.SCAN_MODE_LOW_POWER) - .setScanMode (ScanSettings.MATCH_MODE_STICKY); - - bluetoothLeScanner.startScan (Arrays.asList (scanFilterBuilder.build()), - scanSettingsBuilder.build(), - this); - } - else - { - bluetoothLeScanner.stopScan (this); - } - } - - public boolean pairBluetoothMidiDevice(String address) - { - BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address); - - if (btDevice == null) - { - Log.d ("JUCE", "failed to create buletooth device from address"); - return false; - } - - return getAndroidMidiDeviceManager().pairBluetoothDevice (btDevice); - } - - public void unpairBluetoothMidiDevice (String address) - { - getAndroidMidiDeviceManager().unpairBluetoothDevice (address); - } - - public void onScanFailed (int errorCode) - { - } - - public void onScanResult (int callbackType, ScanResult result) - { - if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES - || callbackType == ScanSettings.CALLBACK_TYPE_FIRST_MATCH) - { - BluetoothDevice device = result.getDevice(); - - if (device != null) - bluetoothMidiDevices.add (device.getAddress()); - } - - if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST) - { - Log.d ("JUCE", "ScanSettings.CALLBACK_TYPE_MATCH_LOST"); - BluetoothDevice device = result.getDevice(); - - if (device != null) - { - bluetoothMidiDevices.remove (device.getAddress()); - unpairBluetoothMidiDevice (device.getAddress()); - } - } - } - - public void onBatchScanResults (List results) - { - for (ScanResult result : results) - onScanResult (ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result); - } - - private BluetoothLeScanner scanner; - private static final String bluetoothLEMidiServiceUUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700"; - - private HashSet bluetoothMidiDevices = new HashSet(); - } - - public static class JuceMidiInputPort extends MidiReceiver implements JuceMidiPort - { - private native void handleReceive (long host, byte[] msg, int offset, int count, long timestamp); - - public JuceMidiInputPort (MidiDeviceManager mm, MidiOutputPort actualPort, MidiPortPath portPathToUse, long hostToUse) - { - owner = mm; - androidPort = actualPort; - portPath = portPathToUse; - juceHost = hostToUse; - isConnected = false; - } - - @Override - protected void finalize() throws Throwable - { - close(); - super.finalize(); - } - - @Override - public boolean isInputPort() - { - return true; - } - - @Override - public void start() - { - if (owner != null && androidPort != null && ! isConnected) { - androidPort.connect(this); - isConnected = true; - } - } - - @Override - public void stop() - { - if (owner != null && androidPort != null && isConnected) { - androidPort.disconnect(this); - isConnected = false; - } - } - - @Override - public void close() - { - if (androidPort != null) { - try { - androidPort.close(); - } catch (IOException exception) { - Log.d("JUCE", "IO Exception while closing port"); - } - } - - if (owner != null) - owner.removePort (portPath); - - owner = null; - androidPort = null; - } - - @Override - public void onSend (byte[] msg, int offset, int count, long timestamp) - { - if (count > 0) - handleReceive (juceHost, msg, offset, count, timestamp); - } - - @Override - public void onFlush() - {} - - @Override - public void sendMidi (byte[] msg, int offset, int count) - { - } - - MidiDeviceManager owner; - MidiOutputPort androidPort; - MidiPortPath portPath; - long juceHost; - boolean isConnected; - } - - public static class JuceMidiOutputPort implements JuceMidiPort - { - public JuceMidiOutputPort (MidiDeviceManager mm, MidiInputPort actualPort, MidiPortPath portPathToUse) - { - owner = mm; - androidPort = actualPort; - portPath = portPathToUse; - } - - @Override - protected void finalize() throws Throwable - { - close(); - super.finalize(); - } - - @Override - public boolean isInputPort() - { - return false; - } - - @Override - public void start() - { - } - - @Override - public void stop() - { - } - - @Override - public void sendMidi (byte[] msg, int offset, int count) - { - if (androidPort != null) - { - try { - androidPort.send(msg, offset, count); - } catch (IOException exception) - { - Log.d ("JUCE", "send midi had IO exception"); - } - } - } - - @Override - public void close() - { - if (androidPort != null) { - try { - androidPort.close(); - } catch (IOException exception) { - Log.d("JUCE", "IO Exception while closing port"); - } - } - - if (owner != null) - owner.removePort (portPath); - - owner = null; - androidPort = null; - } - - MidiDeviceManager owner; - MidiInputPort androidPort; - MidiPortPath portPath; - } - - private static class MidiPortPath extends Object - { - public MidiPortPath (int deviceIdToUse, boolean direction, int androidIndex) - { - deviceId = deviceIdToUse; - isInput = direction; - portIndex = androidIndex; - - } - - public int deviceId; - public int portIndex; - public boolean isInput; - - @Override - public int hashCode() - { - Integer i = new Integer ((deviceId * 128) + (portIndex < 128 ? portIndex : 127)); - return i.hashCode() * (isInput ? -1 : 1); - } - - @Override - public boolean equals (Object obj) - { - if (obj == null) - return false; - - if (getClass() != obj.getClass()) - return false; - - MidiPortPath other = (MidiPortPath) obj; - return (portIndex == other.portIndex && isInput == other.isInput && deviceId == other.deviceId); - } - } - - //============================================================================== - public class MidiDeviceManager extends MidiManager.DeviceCallback implements MidiManager.OnDeviceOpenedListener - { - //============================================================================== - private class DummyBluetoothGattCallback extends BluetoothGattCallback - { - public DummyBluetoothGattCallback (MidiDeviceManager mm) - { - super(); - owner = mm; - } - - public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) - { - if (newState == BluetoothProfile.STATE_CONNECTED) - { - gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH); - owner.pairBluetoothDeviceStepTwo (gatt.getDevice()); - } - } - public void onServicesDiscovered(BluetoothGatt gatt, int status) {} - public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {} - public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {} - public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {} - public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {} - public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {} - public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {} - public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {} - public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {} - - private MidiDeviceManager owner; - } - - //============================================================================== - private class MidiDeviceOpenTask extends java.util.TimerTask - { - public MidiDeviceOpenTask (MidiDeviceManager deviceManager, MidiDevice device, BluetoothGatt gattToUse) - { - owner = deviceManager; - midiDevice = device; - btGatt = gattToUse; - } - - @Override - public boolean cancel() - { - synchronized (MidiDeviceOpenTask.class) - { - owner = null; - boolean retval = super.cancel(); - - if (btGatt != null) - { - btGatt.disconnect(); - btGatt.close(); - - btGatt = null; - } - - if (midiDevice != null) - { - try - { - midiDevice.close(); - } - catch (IOException e) - {} - - midiDevice = null; - } - - return retval; - } - } - - public String getBluetoothAddress() - { - synchronized (MidiDeviceOpenTask.class) - { - if (midiDevice != null) - { - MidiDeviceInfo info = midiDevice.getInfo(); - if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) - { - BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); - if (btDevice != null) - return btDevice.getAddress(); - } - } - } - - return ""; - } - - public BluetoothGatt getGatt() { return btGatt; } - - public int getID() - { - return midiDevice.getInfo().getId(); - } - - @Override - public void run() - { - synchronized (MidiDeviceOpenTask.class) - { - if (owner != null && midiDevice != null) - owner.onDeviceOpenedDelayed (midiDevice); - } - } - - private MidiDeviceManager owner; - private MidiDevice midiDevice; - private BluetoothGatt btGatt; - } - - //============================================================================== - public MidiDeviceManager() - { - manager = (MidiManager) getSystemService (MIDI_SERVICE); - - if (manager == null) - { - Log.d ("JUCE", "MidiDeviceManager error: could not get MidiManager system service"); - return; - } - - openPorts = new HashMap> (); - midiDevices = new ArrayList>(); - openTasks = new HashMap(); - btDevicesPairing = new HashMap(); - - MidiDeviceInfo[] foundDevices = manager.getDevices(); - for (MidiDeviceInfo info : foundDevices) - onDeviceAdded (info); - - manager.registerDeviceCallback (this, null); - } - - protected void finalize() throws Throwable - { - manager.unregisterDeviceCallback (this); - - synchronized (MidiDeviceManager.class) - { - btDevicesPairing.clear(); - - for (Integer deviceID : openTasks.keySet()) - openTasks.get (deviceID).cancel(); - - openTasks = null; - } - - for (MidiPortPath key : openPorts.keySet()) - openPorts.get (key).get().close(); - - openPorts = null; - - for (Pair device : midiDevices) - { - if (device.second != null) - { - device.second.disconnect(); - device.second.close(); - } - - device.first.close(); - } - - midiDevices.clear(); - - super.finalize(); - } - - public String[] getJuceAndroidMidiInputDevices() - { - return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_OUTPUT); - } - - public String[] getJuceAndroidMidiOutputDevices() - { - return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_INPUT); - } - - private String[] getJuceAndroidMidiDevices (int portType) - { - // only update the list when JUCE asks for a new list - synchronized (MidiDeviceManager.class) - { - deviceInfos = getDeviceInfos(); - } - - ArrayList portNames = new ArrayList(); - - int index = 0; - for (MidiPortPath portInfo = getPortPathForJuceIndex (portType, index); portInfo != null; portInfo = getPortPathForJuceIndex (portType, ++index)) - portNames.add (getPortName (portInfo)); - - String[] names = new String[portNames.size()]; - return portNames.toArray (names); - } - - private JuceMidiPort openMidiPortWithJuceIndex (int index, long host, boolean isInput) - { - synchronized (MidiDeviceManager.class) - { - int portTypeToFind = (isInput ? MidiDeviceInfo.PortInfo.TYPE_OUTPUT : MidiDeviceInfo.PortInfo.TYPE_INPUT); - MidiPortPath portInfo = getPortPathForJuceIndex (portTypeToFind, index); - - if (portInfo != null) - { - // ports must be opened exclusively! - if (openPorts.containsKey (portInfo)) - return null; - - Pair devicePair = getMidiDevicePairForId (portInfo.deviceId); - - if (devicePair != null) - { - MidiDevice device = devicePair.first; - if (device != null) - { - JuceMidiPort juceMidiPort = null; - - if (isInput) - { - MidiOutputPort outputPort = device.openOutputPort(portInfo.portIndex); - - if (outputPort != null) - juceMidiPort = new JuceMidiInputPort(this, outputPort, portInfo, host); - } - else - { - MidiInputPort inputPort = device.openInputPort(portInfo.portIndex); - - if (inputPort != null) - juceMidiPort = new JuceMidiOutputPort(this, inputPort, portInfo); - } - - if (juceMidiPort != null) - { - openPorts.put(portInfo, new WeakReference(juceMidiPort)); - - return juceMidiPort; - } - } - } - } - } - - return null; - } - - public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host) - { - return openMidiPortWithJuceIndex (index, host, true); - } - - public JuceMidiPort openMidiOutputPortWithJuceIndex (int index) - { - return openMidiPortWithJuceIndex (index, 0, false); - } - - /* 0: unpaired, 1: paired, 2: pairing */ - public int getBluetoothDeviceStatus (String address) - { - synchronized (MidiDeviceManager.class) - { - if (! address.isEmpty()) - { - if (findMidiDeviceForBluetoothAddress (address) != null) - return 1; - - if (btDevicesPairing.containsKey (address)) - return 2; - - if (findOpenTaskForBluetoothAddress (address) != null) - return 2; - } - } - - return 0; - } - - public boolean pairBluetoothDevice (BluetoothDevice btDevice) - { - String btAddress = btDevice.getAddress(); - if (btAddress.isEmpty()) - return false; - - synchronized (MidiDeviceManager.class) - { - if (getBluetoothDeviceStatus (btAddress) != 0) - return false; - - - btDevicesPairing.put (btDevice.getAddress(), null); - BluetoothGatt gatt = btDevice.connectGatt (getApplicationContext(), true, new DummyBluetoothGattCallback (this)); - - if (gatt != null) - { - btDevicesPairing.put (btDevice.getAddress(), gatt); - } - else - { - pairBluetoothDeviceStepTwo (btDevice); - } - } - - return true; - } - - public void pairBluetoothDeviceStepTwo (BluetoothDevice btDevice) - { - manager.openBluetoothDevice(btDevice, this, null); - } - - public void unpairBluetoothDevice (String address) - { - if (address.isEmpty()) - return; - - synchronized (MidiDeviceManager.class) - { - if (btDevicesPairing.containsKey (address)) - { - BluetoothGatt gatt = btDevicesPairing.get (address); - if (gatt != null) - { - gatt.disconnect(); - gatt.close(); - } - - btDevicesPairing.remove (address); - } - - MidiDeviceOpenTask openTask = findOpenTaskForBluetoothAddress (address); - if (openTask != null) - { - int deviceID = openTask.getID(); - openTask.cancel(); - openTasks.remove (deviceID); - } - - Pair midiDevicePair = findMidiDeviceForBluetoothAddress (address); - if (midiDevicePair != null) - { - MidiDevice midiDevice = midiDevicePair.first; - onDeviceRemoved (midiDevice.getInfo()); - - try { - midiDevice.close(); - } - catch (IOException exception) - { - Log.d ("JUCE", "IOException while closing midi device"); - } - } - } - } - - private Pair findMidiDeviceForBluetoothAddress (String address) - { - for (Pair midiDevice : midiDevices) - { - MidiDeviceInfo info = midiDevice.first.getInfo(); - if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) - { - BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); - if (btDevice != null && btDevice.getAddress().equals (address)) - return midiDevice; - } - } - - return null; - } - - private MidiDeviceOpenTask findOpenTaskForBluetoothAddress (String address) - { - for (Integer deviceID : openTasks.keySet()) - { - MidiDeviceOpenTask openTask = openTasks.get (deviceID); - if (openTask.getBluetoothAddress().equals (address)) - return openTask; - } - - return null; - } - - public void removePort (MidiPortPath path) - { - openPorts.remove (path); - } - - public String getInputPortNameForJuceIndex (int index) - { - MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_OUTPUT, index); - if (portInfo != null) - return getPortName (portInfo); - - return ""; - } - - public String getOutputPortNameForJuceIndex (int index) - { - MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_INPUT, index); - if (portInfo != null) - return getPortName (portInfo); - - return ""; - } - - public void onDeviceAdded (MidiDeviceInfo info) - { - // only add standard midi devices - if (info.getType() == info.TYPE_BLUETOOTH) - return; - - manager.openDevice (info, this, null); - } - - public void onDeviceRemoved (MidiDeviceInfo info) - { - synchronized (MidiDeviceManager.class) - { - Pair devicePair = getMidiDevicePairForId (info.getId()); - - if (devicePair != null) - { - MidiDevice midiDevice = devicePair.first; - BluetoothGatt gatt = devicePair.second; - - // close all ports that use this device - boolean removedPort = true; - - while (removedPort == true) - { - removedPort = false; - for (MidiPortPath key : openPorts.keySet()) - { - if (key.deviceId == info.getId()) - { - openPorts.get(key).get().close(); - removedPort = true; - break; - } - } - } - - if (gatt != null) - { - gatt.disconnect(); - gatt.close(); - } - - midiDevices.remove (devicePair); - } - } - } - - public void onDeviceStatusChanged (MidiDeviceStatus status) - { - } - - @Override - public void onDeviceOpened (MidiDevice theDevice) - { - synchronized (MidiDeviceManager.class) - { - MidiDeviceInfo info = theDevice.getInfo(); - int deviceID = info.getId(); - BluetoothGatt gatt = null; - boolean isBluetooth = false; - - if (! openTasks.containsKey (deviceID)) - { - if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) - { - isBluetooth = true; - BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); - if (btDevice != null) - { - String btAddress = btDevice.getAddress(); - if (btDevicesPairing.containsKey (btAddress)) - { - gatt = btDevicesPairing.get (btAddress); - btDevicesPairing.remove (btAddress); - } - else - { - // unpair was called in the mean time - try - { - Pair midiDevicePair = findMidiDeviceForBluetoothAddress (btDevice.getAddress()); - if (midiDevicePair != null) - { - gatt = midiDevicePair.second; - - if (gatt != null) - { - gatt.disconnect(); - gatt.close(); - } - } - - theDevice.close(); - } - catch (IOException e) - {} - - return; - } - } - } - - MidiDeviceOpenTask openTask = new MidiDeviceOpenTask (this, theDevice, gatt); - openTasks.put (deviceID, openTask); - - new java.util.Timer().schedule (openTask, (isBluetooth ? 2000 : 100)); - } - } - } - - public void onDeviceOpenedDelayed (MidiDevice theDevice) - { - synchronized (MidiDeviceManager.class) - { - int deviceID = theDevice.getInfo().getId(); - - if (openTasks.containsKey (deviceID)) - { - if (! midiDevices.contains(theDevice)) - { - BluetoothGatt gatt = openTasks.get (deviceID).getGatt(); - openTasks.remove (deviceID); - midiDevices.add (new Pair (theDevice, gatt)); - } - } - else - { - // unpair was called in the mean time - MidiDeviceInfo info = theDevice.getInfo(); - BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); - if (btDevice != null) - { - String btAddress = btDevice.getAddress(); - Pair midiDevicePair = findMidiDeviceForBluetoothAddress (btDevice.getAddress()); - if (midiDevicePair != null) - { - BluetoothGatt gatt = midiDevicePair.second; - - if (gatt != null) - { - gatt.disconnect(); - gatt.close(); - } - } - } - - try - { - theDevice.close(); - } - catch (IOException e) - {} - } - } - } - - public String getPortName(MidiPortPath path) - { - int portTypeToFind = (path.isInput ? MidiDeviceInfo.PortInfo.TYPE_INPUT : MidiDeviceInfo.PortInfo.TYPE_OUTPUT); - - synchronized (MidiDeviceManager.class) - { - for (MidiDeviceInfo info : deviceInfos) - { - int localIndex = 0; - if (info.getId() == path.deviceId) - { - for (MidiDeviceInfo.PortInfo portInfo : info.getPorts()) - { - int portType = portInfo.getType(); - if (portType == portTypeToFind) - { - int portIndex = portInfo.getPortNumber(); - if (portIndex == path.portIndex) - { - String portName = portInfo.getName(); - if (portName.isEmpty()) - portName = (String) info.getProperties().get(info.PROPERTY_NAME); - - return portName; - } - } - } - } - } - } - - return ""; - } - - public MidiPortPath getPortPathForJuceIndex (int portType, int juceIndex) - { - int portIdx = 0; - for (MidiDeviceInfo info : deviceInfos) - { - for (MidiDeviceInfo.PortInfo portInfo : info.getPorts()) - { - if (portInfo.getType() == portType) - { - if (portIdx == juceIndex) - return new MidiPortPath (info.getId(), - (portType == MidiDeviceInfo.PortInfo.TYPE_INPUT), - portInfo.getPortNumber()); - - portIdx++; - } - } - } - - return null; - } - - private MidiDeviceInfo[] getDeviceInfos() - { - synchronized (MidiDeviceManager.class) - { - MidiDeviceInfo[] infos = new MidiDeviceInfo[midiDevices.size()]; - - int idx = 0; - for (Pair midiDevice : midiDevices) - infos[idx++] = midiDevice.first.getInfo(); - - return infos; - } - } - - private Pair getMidiDevicePairForId (int deviceId) - { - synchronized (MidiDeviceManager.class) - { - for (Pair midiDevice : midiDevices) - if (midiDevice.first.getInfo().getId() == deviceId) - return midiDevice; - } - - return null; - } - - private MidiManager manager; - private HashMap btDevicesPairing; - private HashMap openTasks; - private ArrayList> midiDevices; - private MidiDeviceInfo[] deviceInfos; - private HashMap> openPorts; - } - - public MidiDeviceManager getAndroidMidiDeviceManager() - { - if (getSystemService (MIDI_SERVICE) == null) - return null; - - synchronized (AudioPerformanceTest.class) - { - if (midiDeviceManager == null) - midiDeviceManager = new MidiDeviceManager(); - } - - return midiDeviceManager; - } - - public BluetoothManager getAndroidBluetoothManager() - { - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - - if (adapter == null) - return null; - - if (adapter.getBluetoothLeScanner() == null) - return null; - - synchronized (AudioPerformanceTest.class) - { - if (bluetoothManager == null) - bluetoothManager = new BluetoothManager(); - } - - return bluetoothManager; - } - - //============================================================================== - @Override - public void onCreate (Bundle savedInstanceState) - { - super.onCreate (savedInstanceState); - - isScreenSaverEnabled = true; - hideActionBar(); - viewHolder = new ViewHolder (this); - setContentView (viewHolder); - - setVolumeControlStream (AudioManager.STREAM_MUSIC); - - permissionCallbackPtrMap = new HashMap(); - appPausedResumedListeners = new HashMap(); - } - - @Override - protected void onDestroy() - { - quitApp(); - super.onDestroy(); - - clearDataCache(); - } - - @Override - protected void onPause() - { - suspendApp(); - - Long[] keys = appPausedResumedListeners.keySet().toArray (new Long[appPausedResumedListeners.keySet().size()]); - - for (Long k : keys) - appPausedResumedListeners.get (k).appPaused(); - - try - { - Thread.sleep (1000); // This is a bit of a hack to avoid some hard-to-track-down - // openGL glitches when pausing/resuming apps.. - } catch (InterruptedException e) {} - - super.onPause(); - } - - @Override - protected void onResume() - { - super.onResume(); - resumeApp(); - - Long[] keys = appPausedResumedListeners.keySet().toArray (new Long[appPausedResumedListeners.keySet().size()]); - - for (Long k : keys) - appPausedResumedListeners.get (k).appResumed(); - } - - @Override - public void onConfigurationChanged (Configuration cfg) - { - super.onConfigurationChanged (cfg); - setContentView (viewHolder); - } - - private void callAppLauncher() - { - launchApp (getApplicationInfo().publicSourceDir, - getApplicationInfo().dataDir); - } - - // Need to override this as the default implementation always finishes the activity. - @Override - public void onBackPressed() - { - ComponentPeerView focusedView = getViewWithFocusOrDefaultView(); - - if (focusedView == null) - return; - - focusedView.backButtonPressed(); - } - - private ComponentPeerView getViewWithFocusOrDefaultView() - { - for (int i = 0; i < viewHolder.getChildCount(); ++i) - { - if (viewHolder.getChildAt (i).hasFocus()) - return (ComponentPeerView) viewHolder.getChildAt (i); - } - - if (viewHolder.getChildCount() > 0) - return (ComponentPeerView) viewHolder.getChildAt (0); - - return null; - } - - //============================================================================== - private void hideActionBar() - { - // get "getActionBar" method - java.lang.reflect.Method getActionBarMethod = null; - try - { - getActionBarMethod = this.getClass().getMethod ("getActionBar"); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (getActionBarMethod == null) return; - - // invoke "getActionBar" method - Object actionBar = null; - try - { - actionBar = getActionBarMethod.invoke (this); - } - catch (java.lang.IllegalArgumentException e) { return; } - catch (java.lang.IllegalAccessException e) { return; } - catch (java.lang.reflect.InvocationTargetException e) { return; } - if (actionBar == null) return; - - // get "hide" method - java.lang.reflect.Method actionBarHideMethod = null; - try - { - actionBarHideMethod = actionBar.getClass().getMethod ("hide"); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (actionBarHideMethod == null) return; - - // invoke "hide" method - try - { - actionBarHideMethod.invoke (actionBar); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - - void requestPermissionsCompat (String[] permissions, int requestCode) - { - Method requestPermissionsMethod = null; - try - { - requestPermissionsMethod = this.getClass().getMethod ("requestPermissions", - String[].class, int.class); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (requestPermissionsMethod == null) return; - - try - { - requestPermissionsMethod.invoke (this, permissions, requestCode); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - - //============================================================================== - private native void launchApp (String appFile, String appDataDir); - private native void quitApp(); - private native void suspendApp(); - private native void resumeApp(); - private native void setScreenSize (int screenWidth, int screenHeight, int dpi); - private native void appActivityResult (int requestCode, int resultCode, Intent data); - private native void appNewIntent (Intent intent); - - //============================================================================== - private ViewHolder viewHolder; - private MidiDeviceManager midiDeviceManager = null; - private BluetoothManager bluetoothManager = null; - private boolean isScreenSaverEnabled; - private java.util.Timer keepAliveTimer; - - public final ComponentPeerView createNewView (boolean opaque, long host) - { - ComponentPeerView v = new ComponentPeerView (this, opaque, host); - viewHolder.addView (v); - addAppPausedResumedListener (v, host); - return v; - } - - public final void deleteView (ComponentPeerView view) - { - removeAppPausedResumedListener (view, view.host); - - view.host = 0; - - ViewGroup group = (ViewGroup) (view.getParent()); - - if (group != null) - group.removeView (view); - } - - public final void deleteNativeSurfaceView (NativeSurfaceView view) - { - ViewGroup group = (ViewGroup) (view.getParent()); - - if (group != null) - group.removeView (view); - } - - final class ViewHolder extends ViewGroup - { - public ViewHolder (Context context) - { - super (context); - setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS); - setFocusable (false); - } - - protected final void onLayout (boolean changed, int left, int top, int right, int bottom) - { - setScreenSize (getWidth(), getHeight(), getDPI()); - - if (isFirstResize) - { - isFirstResize = false; - callAppLauncher(); - } - } - - private final int getDPI() - { - DisplayMetrics metrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics (metrics); - return metrics.densityDpi; - } - - private boolean isFirstResize = true; - } - - public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom) - { - canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE); - } - - //============================================================================== - public final void setScreenSaver (boolean enabled) - { - if (isScreenSaverEnabled != enabled) - { - isScreenSaverEnabled = enabled; - - if (keepAliveTimer != null) - { - keepAliveTimer.cancel(); - keepAliveTimer = null; - } - - if (enabled) - { - getWindow().clearFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - else - { - getWindow().addFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - - // If no user input is received after about 3 seconds, the OS will lower the - // task's priority, so this timer forces it to be kept active. - keepAliveTimer = new java.util.Timer(); - - keepAliveTimer.scheduleAtFixedRate (new TimerTask() - { - @Override - public void run() - { - android.app.Instrumentation instrumentation = new android.app.Instrumentation(); - - try - { - instrumentation.sendKeyDownUpSync (KeyEvent.KEYCODE_UNKNOWN); - } - catch (Exception e) - { - } - } - }, 2000, 2000); - } - } - } - - public final boolean getScreenSaver() - { - return isScreenSaverEnabled; - } - - //============================================================================== - public final String getClipboardContent() - { - ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE); - - CharSequence content = clipboard.getText(); - return content != null ? content.toString() : new String(); - } - - public final void setClipboardContent (String newText) - { - ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE); - clipboard.setText (newText); - } - - //============================================================================== - public final void showMessageBox (String title, String message, final long callback) - { - AlertDialog.Builder builder = new AlertDialog.Builder (this); - builder.setTitle (title) - .setMessage (message) - .setCancelable (true) - .setOnCancelListener (new DialogInterface.OnCancelListener() - { - public void onCancel (DialogInterface dialog) - { - AudioPerformanceTest.this.alertDismissed (callback, 0); - } - }) - .setPositiveButton ("OK", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - AudioPerformanceTest.this.alertDismissed (callback, 0); - } - }); - - builder.create().show(); - } - - public final void showOkCancelBox (String title, String message, final long callback, - String okButtonText, String cancelButtonText) - { - AlertDialog.Builder builder = new AlertDialog.Builder (this); - builder.setTitle (title) - .setMessage (message) - .setCancelable (true) - .setOnCancelListener (new DialogInterface.OnCancelListener() - { - public void onCancel (DialogInterface dialog) - { - AudioPerformanceTest.this.alertDismissed (callback, 0); - } - }) - .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - AudioPerformanceTest.this.alertDismissed (callback, 1); - } - }) - .setNegativeButton (cancelButtonText.isEmpty() ? "Cancel" : cancelButtonText, new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - AudioPerformanceTest.this.alertDismissed (callback, 0); - } - }); - - builder.create().show(); - } - - public final void showYesNoCancelBox (String title, String message, final long callback) - { - AlertDialog.Builder builder = new AlertDialog.Builder (this); - builder.setTitle (title) - .setMessage (message) - .setCancelable (true) - .setOnCancelListener (new DialogInterface.OnCancelListener() - { - public void onCancel (DialogInterface dialog) - { - AudioPerformanceTest.this.alertDismissed (callback, 0); - } - }) - .setPositiveButton ("Yes", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - AudioPerformanceTest.this.alertDismissed (callback, 1); - } - }) - .setNegativeButton ("No", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - AudioPerformanceTest.this.alertDismissed (callback, 2); - } - }) - .setNeutralButton ("Cancel", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - AudioPerformanceTest.this.alertDismissed (callback, 0); - } - }); - - builder.create().show(); - } - - public native void alertDismissed (long callback, int id); - - //============================================================================== - public interface AppPausedResumedListener - { - void appPaused(); - void appResumed(); - } - - private Map appPausedResumedListeners; - - public void addAppPausedResumedListener (AppPausedResumedListener l, long listenerHost) - { - appPausedResumedListeners.put (new Long (listenerHost), l); - } - - public void removeAppPausedResumedListener (AppPausedResumedListener l, long listenerHost) - { - appPausedResumedListeners.remove (new Long (listenerHost)); - } - - //============================================================================== - public final class ComponentPeerView extends ViewGroup - implements View.OnFocusChangeListener, AppPausedResumedListener - { - public ComponentPeerView (Context context, boolean opaque_, long host) - { - super (context); - this.host = host; - setWillNotDraw (false); - opaque = opaque_; - - setFocusable (true); - setFocusableInTouchMode (true); - setOnFocusChangeListener (this); - - // swap red and blue colours to match internal opengl texture format - ColorMatrix colorMatrix = new ColorMatrix(); - - float[] colorTransform = { 0, 0, 1.0f, 0, 0, - 0, 1.0f, 0, 0, 0, - 1.0f, 0, 0, 0, 0, - 0, 0, 0, 1.0f, 0 }; - - colorMatrix.set (colorTransform); - paint.setColorFilter (new ColorMatrixColorFilter (colorMatrix)); - - java.lang.reflect.Method method = null; - - try - { - method = getClass().getMethod ("setLayerType", int.class, Paint.class); - } - catch (SecurityException e) {} - catch (NoSuchMethodException e) {} - - if (method != null) - { - try - { - int layerTypeNone = 0; - method.invoke (this, layerTypeNone, null); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - } - - //============================================================================== - private native void handlePaint (long host, Canvas canvas, Paint paint); - - @Override - public void onDraw (Canvas canvas) - { - if (host == 0) - return; - - handlePaint (host, canvas, paint); - } - - @Override - public boolean isOpaque() - { - return opaque; - } - - private boolean opaque; - private long host; - private Paint paint = new Paint(); - - //============================================================================== - private native void handleMouseDown (long host, int index, float x, float y, long time); - private native void handleMouseDrag (long host, int index, float x, float y, long time); - private native void handleMouseUp (long host, int index, float x, float y, long time); - - @Override - public boolean onTouchEvent (MotionEvent event) - { - if (host == 0) - return false; - - int action = event.getAction(); - long time = event.getEventTime(); - - switch (action & MotionEvent.ACTION_MASK) - { - case MotionEvent.ACTION_DOWN: - handleMouseDown (host, event.getPointerId(0), event.getX(), event.getY(), time); - return true; - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - handleMouseUp (host, event.getPointerId(0), event.getX(), event.getY(), time); - return true; - - case MotionEvent.ACTION_MOVE: - { - int n = event.getPointerCount(); - for (int i = 0; i < n; ++i) - handleMouseDrag (host, event.getPointerId(i), event.getX(i), event.getY(i), time); - - return true; - } - - case MotionEvent.ACTION_POINTER_UP: - { - int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - handleMouseUp (host, event.getPointerId(i), event.getX(i), event.getY(i), time); - return true; - } - - case MotionEvent.ACTION_POINTER_DOWN: - { - int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - handleMouseDown (host, event.getPointerId(i), event.getX(i), event.getY(i), time); - return true; - } - - default: - break; - } - - return false; - } - - //============================================================================== - private native void handleKeyDown (long host, int keycode, int textchar); - private native void handleKeyUp (long host, int keycode, int textchar); - private native void handleBackButton (long host); - private native void handleKeyboardHidden (long host); - - public void showKeyboard (String type) - { - InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE); - - if (imm != null) - { - if (type.length() > 0) - { - imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT); - imm.setInputMethod (getWindowToken(), type); - keyboardDismissListener.startListening(); - } - else - { - imm.hideSoftInputFromWindow (getWindowToken(), 0); - keyboardDismissListener.stopListening(); - } - } - } - - public void backButtonPressed() - { - if (host == 0) - return; - - handleBackButton (host); - } - - @Override - public boolean onKeyDown (int keyCode, KeyEvent event) - { - if (host == 0) - return false; - - switch (keyCode) - { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - return super.onKeyDown (keyCode, event); - case KeyEvent.KEYCODE_BACK: - { - ((Activity) getContext()).onBackPressed(); - return true; - } - - default: - break; - } - - handleKeyDown (host, keyCode, event.getUnicodeChar()); - return true; - } - - @Override - public boolean onKeyUp (int keyCode, KeyEvent event) - { - if (host == 0) - return false; - - handleKeyUp (host, keyCode, event.getUnicodeChar()); - return true; - } - - @Override - public boolean onKeyMultiple (int keyCode, int count, KeyEvent event) - { - if (host == 0) - return false; - - if (keyCode != KeyEvent.KEYCODE_UNKNOWN || event.getAction() != KeyEvent.ACTION_MULTIPLE) - return super.onKeyMultiple (keyCode, count, event); - - if (event.getCharacters() != null) - { - int utf8Char = event.getCharacters().codePointAt (0); - handleKeyDown (host, utf8Char, utf8Char); - return true; - } - - return false; - } - - //============================================================================== - private final class KeyboardDismissListener - { - public KeyboardDismissListener (ComponentPeerView viewToUse) - { - view = viewToUse; - } - - private void startListening() - { - view.getViewTreeObserver().addOnGlobalLayoutListener(viewTreeObserver); - } - - private void stopListening() - { - view.getViewTreeObserver().removeGlobalOnLayoutListener(viewTreeObserver); - } - - private class TreeObserver implements ViewTreeObserver.OnGlobalLayoutListener - { - TreeObserver() - { - keyboardShown = false; - } - - @Override - public void onGlobalLayout() - { - Rect r = new Rect(); - - ViewGroup parentView = (ViewGroup) getParent(); - - if (parentView == null) - return; - - parentView.getWindowVisibleDisplayFrame (r); - - int diff = parentView.getHeight() - (r.bottom - r.top); - - // Arbitrary threshold, surely keyboard would take more than 20 pix. - if (diff < 20 && keyboardShown) - { - keyboardShown = false; - handleKeyboardHidden (view.host); - } - - if (! keyboardShown && diff > 20) - keyboardShown = true; - }; - - private boolean keyboardShown; - }; - - private ComponentPeerView view; - private TreeObserver viewTreeObserver = new TreeObserver(); - } - - private KeyboardDismissListener keyboardDismissListener = new KeyboardDismissListener(this); - - // this is here to make keyboard entry work on a Galaxy Tab2 10.1 - @Override - public InputConnection onCreateInputConnection (EditorInfo outAttrs) - { - outAttrs.actionLabel = ""; - outAttrs.hintText = ""; - outAttrs.initialCapsMode = 0; - outAttrs.initialSelEnd = outAttrs.initialSelStart = -1; - outAttrs.label = ""; - outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI; - outAttrs.inputType = InputType.TYPE_NULL; - - return new BaseInputConnection (this, false); - } - - //============================================================================== - @Override - protected void onSizeChanged (int w, int h, int oldw, int oldh) - { - if (host == 0) - return; - - super.onSizeChanged (w, h, oldw, oldh); - viewSizeChanged (host); - } - - @Override - protected void onLayout (boolean changed, int left, int top, int right, int bottom) - { - for (int i = getChildCount(); --i >= 0;) - requestTransparentRegion (getChildAt (i)); - } - - private native void viewSizeChanged (long host); - - @Override - public void onFocusChange (View v, boolean hasFocus) - { - if (host == 0) - return; - - if (v == this) - focusChanged (host, hasFocus); - } - - private native void focusChanged (long host, boolean hasFocus); - - public void setViewName (String newName) {} - - public void setSystemUiVisibilityCompat (int visibility) - { - Method systemUIVisibilityMethod = null; - try - { - systemUIVisibilityMethod = this.getClass().getMethod ("setSystemUiVisibility", int.class); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (systemUIVisibilityMethod == null) return; - - try - { - systemUIVisibilityMethod.invoke (this, visibility); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - - public boolean isVisible() { return getVisibility() == VISIBLE; } - public void setVisible (boolean b) { setVisibility (b ? VISIBLE : INVISIBLE); } - - public boolean containsPoint (int x, int y) - { - return true; //xxx needs to check overlapping views - } - - //============================================================================== - private native void handleAppPaused (long host); - private native void handleAppResumed (long host); - - @Override - public void appPaused() - { - if (host == 0) - return; - - handleAppPaused (host); - } - - @Override - public void appResumed() - { - if (host == 0) - return; - - // Ensure that navigation/status bar visibility is correctly restored. - handleAppResumed (host); - } - } - - //============================================================================== - public static class NativeSurfaceView extends SurfaceView - implements SurfaceHolder.Callback - { - private long nativeContext = 0; - private boolean forVideo; - - NativeSurfaceView (Context context, long nativeContextPtr, boolean createdForVideo) - { - super (context); - nativeContext = nativeContextPtr; - forVideo = createdForVideo; - } - - public Surface getNativeSurface() - { - Surface retval = null; - - SurfaceHolder holder = getHolder(); - if (holder != null) - retval = holder.getSurface(); - - return retval; - } - - //============================================================================== - @Override - public void surfaceChanged (SurfaceHolder holder, int format, int width, int height) - { - if (forVideo) - surfaceChangedNativeVideo (nativeContext, holder, format, width, height); - else - surfaceChangedNative (nativeContext, holder, format, width, height); - } - - @Override - public void surfaceCreated (SurfaceHolder holder) - { - if (forVideo) - surfaceCreatedNativeVideo (nativeContext, holder); - else - surfaceCreatedNative (nativeContext, holder); - } - - @Override - public void surfaceDestroyed (SurfaceHolder holder) - { - if (forVideo) - surfaceDestroyedNativeVideo (nativeContext, holder); - else - surfaceDestroyedNative (nativeContext, holder); - } - - @Override - protected void dispatchDraw (Canvas canvas) - { - super.dispatchDraw (canvas); - - if (forVideo) - dispatchDrawNativeVideo (nativeContext, canvas); - else - dispatchDrawNative (nativeContext, canvas); - } - - //============================================================================== - @Override - protected void onAttachedToWindow() - { - super.onAttachedToWindow(); - getHolder().addCallback (this); - } - - @Override - protected void onDetachedFromWindow() - { - super.onDetachedFromWindow(); - getHolder().removeCallback (this); - } - - //============================================================================== - private native void dispatchDrawNative (long nativeContextPtr, Canvas canvas); - private native void surfaceCreatedNative (long nativeContextptr, SurfaceHolder holder); - private native void surfaceDestroyedNative (long nativeContextptr, SurfaceHolder holder); - private native void surfaceChangedNative (long nativeContextptr, SurfaceHolder holder, - int format, int width, int height); - - private native void dispatchDrawNativeVideo (long nativeContextPtr, Canvas canvas); - private native void surfaceCreatedNativeVideo (long nativeContextptr, SurfaceHolder holder); - private native void surfaceDestroyedNativeVideo (long nativeContextptr, SurfaceHolder holder); - private native void surfaceChangedNativeVideo (long nativeContextptr, SurfaceHolder holder, - int format, int width, int height); - } - - public NativeSurfaceView createNativeSurfaceView (long nativeSurfacePtr, boolean forVideo) - { - return new NativeSurfaceView (this, nativeSurfacePtr, forVideo); - } - - //============================================================================== - public final int[] renderGlyph (char glyph1, char glyph2, Paint paint, android.graphics.Matrix matrix, Rect bounds) - { - Path p = new Path(); - - char[] str = { glyph1, glyph2 }; - paint.getTextPath (str, 0, (glyph2 != 0 ? 2 : 1), 0.0f, 0.0f, p); - - RectF boundsF = new RectF(); - p.computeBounds (boundsF, true); - matrix.mapRect (boundsF); - - boundsF.roundOut (bounds); - bounds.left--; - bounds.right++; - - final int w = bounds.width(); - final int h = Math.max (1, bounds.height()); - - Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888); - - Canvas c = new Canvas (bm); - matrix.postTranslate (-bounds.left, -bounds.top); - c.setMatrix (matrix); - c.drawPath (p, paint); - - final int sizeNeeded = w * h; - if (cachedRenderArray.length < sizeNeeded) - cachedRenderArray = new int [sizeNeeded]; - - bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h); - bm.recycle(); - return cachedRenderArray; - } - - private int[] cachedRenderArray = new int [256]; - - //============================================================================== - public static class NativeInvocationHandler implements InvocationHandler - { - public NativeInvocationHandler (Activity activityToUse, long nativeContextRef) - { - activity = activityToUse; - nativeContext = nativeContextRef; - } - - public void nativeContextDeleted() - { - nativeContext = 0; - } - - @Override - public void finalize() - { - activity.runOnUiThread (new Runnable() - { - @Override - public void run() - { - if (nativeContext != 0) - dispatchFinalize (nativeContext); - } - }); - } - - @Override - public Object invoke (Object proxy, Method method, Object[] args) throws Throwable - { - return dispatchInvoke (nativeContext, proxy, method, args); - } - - //============================================================================== - Activity activity; - private long nativeContext = 0; - - private native void dispatchFinalize (long nativeContextRef); - private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args); - } - - public InvocationHandler createInvocationHandler (long nativeContextRef) - { - return new NativeInvocationHandler (this, nativeContextRef); - } - - public void invocationHandlerContextDeleted (InvocationHandler handler) - { - ((NativeInvocationHandler) handler).nativeContextDeleted(); - } - - //============================================================================== - public static class HTTPStream - { - public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, - String headersToUse, int timeOutMsToUse, - int[] statusCodeToUse, StringBuffer responseHeadersToUse, - int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException - { - isPost = isPostToUse; - postData = postDataToUse; - headers = headersToUse; - timeOutMs = timeOutMsToUse; - statusCode = statusCodeToUse; - responseHeaders = responseHeadersToUse; - totalLength = -1; - numRedirectsToFollow = numRedirectsToFollowToUse; - httpRequestCmd = httpRequestCmdToUse; - - connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); - } - - private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, - String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException - { - HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); - - try - { - newConnection.setInstanceFollowRedirects (false); - newConnection.setConnectTimeout (timeOutMs); - newConnection.setReadTimeout (timeOutMs); - - // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. - // So convert headers string to an array, with an element for each line - String headerLines[] = headers.split("\\n"); - - // Set request headers - for (int i = 0; i < headerLines.length; ++i) - { - int pos = headerLines[i].indexOf (":"); - - if (pos > 0 && pos < headerLines[i].length()) - { - String field = headerLines[i].substring (0, pos); - String value = headerLines[i].substring (pos + 1); - - if (value.length() > 0) - newConnection.setRequestProperty (field, value); - } - } - - newConnection.setRequestMethod (httpRequestCmd); - - if (isPost) - { - newConnection.setDoOutput (true); - - if (postData != null) - { - OutputStream out = newConnection.getOutputStream(); - out.write(postData); - out.flush(); - } - } - - return newConnection; - } - catch (Throwable e) - { - newConnection.disconnect(); - throw new IOException ("Connection error"); - } - } - - private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException - { - synchronized (createFutureLock) - { - if (hasBeenCancelled.get()) - return null; - - streamFuture = executor.submit (new Callable() - { - @Override - public BufferedInputStream call() throws IOException - { - return new BufferedInputStream (isInput ? connection.getInputStream() - : connection.getErrorStream()); - } - }); - } - - try - { - return streamFuture.get(); - } - catch (InterruptedException e) - { - return null; - } - catch (CancellationException e) - { - return null; - } - } - - public final boolean connect() - { - boolean result = false; - int numFollowedRedirects = 0; - - while (true) - { - result = doConnect(); - - if (! result) - return false; - - if (++numFollowedRedirects > numRedirectsToFollow) - break; - - int status = statusCode[0]; - - if (status == 301 || status == 302 || status == 303 || status == 307) - { - // Assumes only one occurrence of "Location" - int pos1 = responseHeaders.indexOf ("Location:") + 10; - int pos2 = responseHeaders.indexOf ("\n", pos1); - - if (pos2 > pos1) - { - String currentLocation = connection.getURL().toString(); - String newLocation = responseHeaders.substring (pos1, pos2); - - try - { - // Handle newLocation whether it's absolute or relative - URL baseUrl = new URL (currentLocation); - URL newUrl = new URL (baseUrl, newLocation); - String transformedNewLocation = newUrl.toString(); - - if (transformedNewLocation != currentLocation) - { - // Clear responseHeaders before next iteration - responseHeaders.delete (0, responseHeaders.length()); - - synchronized (createStreamLock) - { - if (hasBeenCancelled.get()) - return false; - - connection.disconnect(); - - try - { - connection = createConnection (transformedNewLocation, isPost, - postData, headers, timeOutMs, - httpRequestCmd); - } - catch (Throwable e) - { - return false; - } - } - } - else - { - break; - } - } - catch (Throwable e) - { - return false; - } - } - else - { - break; - } - } - else - { - break; - } - } - - return result; - } - - private final boolean doConnect() - { - synchronized (createStreamLock) - { - if (hasBeenCancelled.get()) - return false; - - try - { - try - { - inputStream = getCancellableStream (true); - } - catch (ExecutionException e) - { - if (connection.getResponseCode() < 400) - { - statusCode[0] = connection.getResponseCode(); - connection.disconnect(); - return false; - } - } - finally - { - statusCode[0] = connection.getResponseCode(); - } - - try - { - if (statusCode[0] >= 400) - inputStream = getCancellableStream (false); - else - inputStream = getCancellableStream (true); - } - catch (ExecutionException e) - {} - - for (java.util.Map.Entry> entry : connection.getHeaderFields().entrySet()) - { - if (entry.getKey() != null && entry.getValue() != null) - { - responseHeaders.append(entry.getKey() + ": " - + android.text.TextUtils.join(",", entry.getValue()) + "\n"); - - if (entry.getKey().compareTo ("Content-Length") == 0) - totalLength = Integer.decode (entry.getValue().get (0)); - } - } - - return true; - } - catch (IOException e) - { - return false; - } - } - } - - static class DisconnectionRunnable implements Runnable - { - public DisconnectionRunnable (HttpURLConnection theConnection, - InputStream theInputStream, - ReentrantLock theCreateStreamLock, - Object theCreateFutureLock, - Future theStreamFuture) - { - connectionToDisconnect = theConnection; - inputStream = theInputStream; - createStreamLock = theCreateStreamLock; - createFutureLock = theCreateFutureLock; - streamFuture = theStreamFuture; - } - - public void run() - { - try - { - if (! createStreamLock.tryLock()) - { - synchronized (createFutureLock) - { - if (streamFuture != null) - streamFuture.cancel (true); - } - - createStreamLock.lock(); - } - - if (connectionToDisconnect != null) - connectionToDisconnect.disconnect(); - - if (inputStream != null) - inputStream.close(); - } - catch (IOException e) - {} - finally - { - createStreamLock.unlock(); - } - } - - private HttpURLConnection connectionToDisconnect; - private InputStream inputStream; - private ReentrantLock createStreamLock; - private Object createFutureLock; - Future streamFuture; - } - - public final void release() - { - DisconnectionRunnable disconnectionRunnable = new DisconnectionRunnable (connection, - inputStream, - createStreamLock, - createFutureLock, - streamFuture); - - synchronized (createStreamLock) - { - hasBeenCancelled.set (true); - - connection = null; - } - - Thread disconnectionThread = new Thread(disconnectionRunnable); - disconnectionThread.start(); - } - - public final int read (byte[] buffer, int numBytes) - { - int num = 0; - - try - { - synchronized (createStreamLock) - { - if (inputStream != null) - num = inputStream.read (buffer, 0, numBytes); - } - } - catch (IOException e) - {} - - if (num > 0) - position += num; - - return num; - } - - public final long getPosition() { return position; } - public final long getTotalLength() { return totalLength; } - public final boolean isExhausted() { return false; } - public final boolean setPosition (long newPos) { return false; } - - private boolean isPost; - private byte[] postData; - private String headers; - private int timeOutMs; - String httpRequestCmd; - private HttpURLConnection connection; - private int[] statusCode; - private StringBuffer responseHeaders; - private int totalLength; - private int numRedirectsToFollow; - private InputStream inputStream; - private long position; - private final ReentrantLock createStreamLock = new ReentrantLock(); - private final Object createFutureLock = new Object(); - private AtomicBoolean hasBeenCancelled = new AtomicBoolean(); - - private final ExecutorService executor = Executors.newCachedThreadPool (Executors.defaultThreadFactory()); - Future streamFuture; - } - - public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData, - String headers, int timeOutMs, int[] statusCode, - StringBuffer responseHeaders, int numRedirectsToFollow, - String httpRequestCmd) - { - // timeout parameter of zero for HttpUrlConnection is a blocking connect (negative value for juce::URL) - if (timeOutMs < 0) - timeOutMs = 0; - else if (timeOutMs == 0) - timeOutMs = 30000; - - for (;;) - { - try - { - HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, - timeOutMs, statusCode, responseHeaders, - numRedirectsToFollow, httpRequestCmd); - - return httpStream; - } - catch (Throwable e) {} - - return null; - } - } - - public final void launchURL (String url) - { - startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url))); - } - - private native boolean webViewPageLoadStarted (long host, WebView view, String url); - private native void webViewPageLoadFinished (long host, WebView view, String url); - private native void webViewReceivedError (long host, WebView view, WebResourceRequest request, WebResourceError error); private native void webViewReceivedHttpError (long host, WebView view, WebResourceRequest request, WebResourceResponse errorResponse); private native void webViewReceivedSslError (long host, WebView view, SslErrorHandler handler, SslError error); - private native void webViewCloseWindowRequest (long host, WebView view); - private native void webViewCreateWindowRequest (long host, WebView view); - - //============================================================================== - public class JuceWebViewClient extends WebViewClient - { - public JuceWebViewClient (long hostToUse) - { - host = hostToUse; - } - - public void hostDeleted() - { - synchronized (hostLock) - { - host = 0; - } - } - - @Override - public void onPageFinished (WebView view, String url) - { - if (host == 0) - return; - - webViewPageLoadFinished (host, view, url); - } - - @Override - public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) - { - if (host == 0) - return; - - webViewReceivedSslError (host, view, handler, error); - } - - @Override - public void onReceivedError (WebView view, WebResourceRequest request, WebResourceError error) - { - if (host == 0) - return; - - webViewReceivedError (host, view, request, error); - } - - @Override - public void onReceivedHttpError (WebView view, WebResourceRequest request, WebResourceResponse errorResponse) - { - if (host == 0) - return; - - webViewReceivedHttpError (host, view, request, errorResponse); - } - - @Override - public WebResourceResponse shouldInterceptRequest (WebView view, WebResourceRequest request) - { - synchronized (hostLock) - { - if (host != 0) - { - boolean shouldLoad = webViewPageLoadStarted (host, view, request.getUrl().toString()); - - if (shouldLoad) - return null; - } - } - - return new WebResourceResponse ("text/html", null, null); - } - - private long host; - private final Object hostLock = new Object(); - } - - public class JuceWebChromeClient extends WebChromeClient - { - public JuceWebChromeClient (long hostToUse) - { - host = hostToUse; - } - - @Override - public void onCloseWindow (WebView window) - { - webViewCloseWindowRequest (host, window); - } - - @Override - public boolean onCreateWindow (WebView view, boolean isDialog, - boolean isUserGesture, Message resultMsg) - { - webViewCreateWindowRequest (host, view); - return false; - } - - private long host; - private final Object hostLock = new Object(); - } - - - //============================================================================== - public class CameraDeviceStateCallback extends CameraDevice.StateCallback - { - private native void cameraDeviceStateClosed (long host, CameraDevice camera); - private native void cameraDeviceStateDisconnected (long host, CameraDevice camera); - private native void cameraDeviceStateError (long host, CameraDevice camera, int error); - private native void cameraDeviceStateOpened (long host, CameraDevice camera); - - CameraDeviceStateCallback (long hostToUse) - { - host = hostToUse; - } - - @Override - public void onClosed (CameraDevice camera) - { - cameraDeviceStateClosed (host, camera); - } - - @Override - public void onDisconnected (CameraDevice camera) - { - cameraDeviceStateDisconnected (host, camera); - } - - @Override - public void onError (CameraDevice camera, int error) - { - cameraDeviceStateError (host, camera, error); - } - - @Override - public void onOpened (CameraDevice camera) - { - cameraDeviceStateOpened (host, camera); - } - - private long host; - } - - //============================================================================== - public class CameraCaptureSessionStateCallback extends CameraCaptureSession.StateCallback - { - private native void cameraCaptureSessionActive (long host, CameraCaptureSession session); - private native void cameraCaptureSessionClosed (long host, CameraCaptureSession session); - private native void cameraCaptureSessionConfigureFailed (long host, CameraCaptureSession session); - private native void cameraCaptureSessionConfigured (long host, CameraCaptureSession session); - private native void cameraCaptureSessionReady (long host, CameraCaptureSession session); - - CameraCaptureSessionStateCallback (long hostToUse) - { - host = hostToUse; - } - - @Override - public void onActive (CameraCaptureSession session) - { - cameraCaptureSessionActive (host, session); - } - - @Override - public void onClosed (CameraCaptureSession session) - { - cameraCaptureSessionClosed (host, session); - } - - @Override - public void onConfigureFailed (CameraCaptureSession session) - { - cameraCaptureSessionConfigureFailed (host, session); - } - - @Override - public void onConfigured (CameraCaptureSession session) - { - cameraCaptureSessionConfigured (host, session); - } - - @Override - public void onReady (CameraCaptureSession session) - { - cameraCaptureSessionReady (host, session); - } - - private long host; - } - - //============================================================================== - public class CameraCaptureSessionCaptureCallback extends CameraCaptureSession.CaptureCallback - { - private native void cameraCaptureSessionCaptureCompleted (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result); - private native void cameraCaptureSessionCaptureFailed (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureFailure failure); - private native void cameraCaptureSessionCaptureProgressed (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult); - private native void cameraCaptureSessionCaptureStarted (long host, boolean isPreview, CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber); - private native void cameraCaptureSessionCaptureSequenceAborted (long host, boolean isPreview, CameraCaptureSession session, int sequenceId); - private native void cameraCaptureSessionCaptureSequenceCompleted (long host, boolean isPreview, CameraCaptureSession session, int sequenceId, long frameNumber); - - CameraCaptureSessionCaptureCallback (long hostToUse, boolean shouldBePreview) - { - host = hostToUse; - preview = shouldBePreview; - } - - @Override - public void onCaptureCompleted (CameraCaptureSession session, CaptureRequest request, - TotalCaptureResult result) - { - cameraCaptureSessionCaptureCompleted (host, preview, session, request, result); - } - - @Override - public void onCaptureFailed (CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) - { - cameraCaptureSessionCaptureFailed (host, preview, session, request, failure); - } - - @Override - public void onCaptureProgressed (CameraCaptureSession session, CaptureRequest request, - CaptureResult partialResult) - { - cameraCaptureSessionCaptureProgressed (host, preview, session, request, partialResult); - } - - @Override - public void onCaptureSequenceAborted (CameraCaptureSession session, int sequenceId) - { - cameraCaptureSessionCaptureSequenceAborted (host, preview, session, sequenceId); - } - - @Override - public void onCaptureSequenceCompleted (CameraCaptureSession session, int sequenceId, long frameNumber) - { - cameraCaptureSessionCaptureSequenceCompleted (host, preview, session, sequenceId, frameNumber); - } - - @Override - public void onCaptureStarted (CameraCaptureSession session, CaptureRequest request, long timestamp, - long frameNumber) - { - cameraCaptureSessionCaptureStarted (host, preview, session, request, timestamp, frameNumber); - } - - private long host; - private boolean preview; - } - - //============================================================================== - public class JuceOrientationEventListener extends OrientationEventListener - { - private native void deviceOrientationChanged (long host, int orientation); - - public JuceOrientationEventListener (long hostToUse, Context context, int rate) - { - super (context, rate); - - host = hostToUse; - } - - @Override - public void onOrientationChanged (int orientation) - { - deviceOrientationChanged (host, orientation); - } - - private long host; - } - - - //============================================================================== - public class MediaControllerCallback extends MediaController.Callback - { - private native void mediaControllerAudioInfoChanged (long host, MediaController.PlaybackInfo info); - private native void mediaControllerMetadataChanged (long host, MediaMetadata metadata); - private native void mediaControllerPlaybackStateChanged (long host, PlaybackState state); - private native void mediaControllerSessionDestroyed (long host); - - MediaControllerCallback (long hostToUse) - { - host = hostToUse; - } - - @Override - public void onAudioInfoChanged (MediaController.PlaybackInfo info) - { - mediaControllerAudioInfoChanged (host, info); - } - - @Override - public void onMetadataChanged (MediaMetadata metadata) - { - mediaControllerMetadataChanged (host, metadata); - } - - @Override - public void onPlaybackStateChanged (PlaybackState state) - { - mediaControllerPlaybackStateChanged (host, state); - } - - @Override - public void onQueueChanged (List queue) {} - - @Override - public void onSessionDestroyed() - { - mediaControllerSessionDestroyed (host); - } - - private long host; - } - - //============================================================================== - public class MediaSessionCallback extends MediaSession.Callback - { - private native void mediaSessionPause (long host); - private native void mediaSessionPlay (long host); - private native void mediaSessionPlayFromMediaId (long host, String mediaId, Bundle extras); - private native void mediaSessionSeekTo (long host, long pos); - private native void mediaSessionStop (long host); - - - MediaSessionCallback (long hostToUse) - { - host = hostToUse; - } - - @Override - public void onPause() - { - mediaSessionPause (host); - } - - @Override - public void onPlay() - { - mediaSessionPlay (host); - } - - @Override - public void onPlayFromMediaId (String mediaId, Bundle extras) - { - mediaSessionPlayFromMediaId (host, mediaId, extras); - } - - @Override - public void onSeekTo (long pos) - { - mediaSessionSeekTo (host, pos); - } - - @Override - public void onStop() - { - mediaSessionStop (host); - } - - @Override - public void onFastForward() {} - - @Override - public boolean onMediaButtonEvent (Intent mediaButtonIntent) - { - return true; - } - - @Override - public void onRewind() {} - - @Override - public void onSkipToNext() {} - - @Override - public void onSkipToPrevious() {} - - @Override - public void onSkipToQueueItem (long id) {} - - private long host; - } - - //============================================================================== - public class SystemVolumeObserver extends ContentObserver - { - private native void mediaSessionSystemVolumeChanged (long host); - - SystemVolumeObserver (Activity activityToUse, long hostToUse) - { - super (null); - - activity = activityToUse; - host = hostToUse; - } - - void setEnabled (boolean shouldBeEnabled) - { - if (shouldBeEnabled) - activity.getApplicationContext().getContentResolver().registerContentObserver (android.provider.Settings.System.CONTENT_URI, true, this); - else - activity.getApplicationContext().getContentResolver().unregisterContentObserver (this); - } - - @Override - public void onChange (boolean selfChange, Uri uri) - { - if (uri.toString().startsWith ("content://settings/system/volume_music")) - mediaSessionSystemVolumeChanged (host); - } - - private Activity activity; - private long host; - } - - - //============================================================================== - public static final String getLocaleValue (boolean isRegion) - { - java.util.Locale locale = java.util.Locale.getDefault(); - - return isRegion ? locale.getCountry() - : locale.getLanguage(); - } - - private static final String getFileLocation (String type) - { - return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); - } - - public static final String getDocumentsFolder() - { - if (getAndroidSDKVersion() >= 19) - return getFileLocation ("Documents"); - - return Environment.getDataDirectory().getAbsolutePath(); - } - - public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } - public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } - public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } - public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); } - - //============================================================================== - @Override - protected void onActivityResult (int requestCode, int resultCode, Intent data) - { - appActivityResult (requestCode, resultCode, data); - } - - @Override - protected void onNewIntent (Intent intent) - { - super.onNewIntent(intent); - setIntent(intent); - - appNewIntent (intent); - } - - //============================================================================== - public final Typeface getTypeFaceFromAsset (String assetName) - { - try - { - return Typeface.createFromAsset (this.getResources().getAssets(), assetName); - } - catch (Throwable e) {} - - return null; - } - - final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); - - public static String bytesToHex (byte[] bytes) - { - char[] hexChars = new char[bytes.length * 2]; - - for (int j = 0; j < bytes.length; ++j) - { - int v = bytes[j] & 0xff; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0f]; - } - - return new String (hexChars); - } - - final private java.util.Map dataCache = new java.util.HashMap(); - - synchronized private final File getDataCacheFile (byte[] data) - { - try - { - java.security.MessageDigest digest = java.security.MessageDigest.getInstance ("MD5"); - digest.update (data); - - String key = bytesToHex (digest.digest()); - - if (dataCache.containsKey (key)) - return (File) dataCache.get (key); - - File f = new File (this.getCacheDir(), "bindata_" + key); - f.delete(); - FileOutputStream os = new FileOutputStream (f); - os.write (data, 0, data.length); - dataCache.put (key, f); - return f; - } - catch (Throwable e) {} - - return null; - } - - private final void clearDataCache() - { - java.util.Iterator it = dataCache.values().iterator(); - - while (it.hasNext()) - { - File f = (File) it.next(); - f.delete(); - } - } - - public final Typeface getTypeFaceFromByteArray (byte[] data) - { - try - { - File f = getDataCacheFile (data); - - if (f != null) - return Typeface.createFromFile (f); - } - catch (Exception e) - { - Log.e ("JUCE", e.toString()); - } - - return null; - } - - public static final int getAndroidSDKVersion() - { - return android.os.Build.VERSION.SDK_INT; - } - - public final String audioManagerGetProperty (String property) - { - Object obj = getSystemService (AUDIO_SERVICE); - if (obj == null) - return null; - - java.lang.reflect.Method method; - - try - { - method = obj.getClass().getMethod ("getProperty", String.class); - } - catch (SecurityException e) { return null; } - catch (NoSuchMethodException e) { return null; } - - if (method == null) - return null; - - try - { - return (String) method.invoke (obj, property); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - - return null; - } - - public final boolean hasSystemFeature (String property) - { - return getPackageManager().hasSystemFeature (property); - } -} diff --git a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/SharingContentProvider.java b/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/SharingContentProvider.java deleted file mode 100644 index 9bf1d88180..0000000000 --- a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/SharingContentProvider.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - ============================================================================== - - 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. - - ============================================================================== -*/ - -package com.juce.audioperformancetest; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.res.AssetFileDescriptor; -import android.content.res.Resources; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.net.Uri; -import android.os.FileObserver; -import android.os.ParcelFileDescriptor; -import java.lang.String; - -public final class SharingContentProvider extends ContentProvider -{ - private Object lock = new Object(); - - private native void contentSharerFileObserverEvent (long host, int event, String path); - - private native Cursor contentSharerQuery (Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder); - - private native void contentSharerCursorClosed (long host); - - private native AssetFileDescriptor contentSharerOpenFile (Uri uri, String mode); - private native String[] contentSharerGetStreamTypes (Uri uri, String mimeTypeFilter); - - public final class ProviderFileObserver extends FileObserver - { - public ProviderFileObserver (long hostToUse, String path, int mask) - { - super (path, mask); - - host = hostToUse; - } - - public void onEvent (int event, String path) - { - contentSharerFileObserverEvent (host, event, path); - } - - private long host; - } - - public final class ProviderCursor extends MatrixCursor - { - ProviderCursor (long hostToUse, String[] columnNames) - { - super (columnNames); - - host = hostToUse; - } - - @Override - public void close() - { - super.close(); - - contentSharerCursorClosed (host); - } - - private long host; - } - - @Override - public boolean onCreate() - { - return true; - } - - @Override - public Cursor query (Uri url, String[] projection, String selection, - String[] selectionArgs, String sortOrder) - { - synchronized (lock) - { - return contentSharerQuery (url, projection, selection, selectionArgs, sortOrder); - } - } - - @Override - public Uri insert (Uri uri, ContentValues values) - { - return null; - } - - @Override - public int update (Uri uri, ContentValues values, String selection, - String[] selectionArgs) - { - return 0; - } - - @Override - public int delete (Uri uri, String selection, String[] selectionArgs) - { - return 0; - } - - @Override - public String getType (Uri uri) - { - return null; - } - - @Override - public AssetFileDescriptor openAssetFile (Uri uri, String mode) - { - synchronized (lock) - { - return contentSharerOpenFile (uri, mode); - } - } - - @Override - public ParcelFileDescriptor openFile (Uri uri, String mode) - { - synchronized (lock) - { - AssetFileDescriptor result = contentSharerOpenFile (uri, mode); - - if (result != null) - return result.getParcelFileDescriptor(); - - return null; - } - } - - @Override - public String[] getStreamTypes (Uri uri, String mimeTypeFilter) - { - synchronized (lock) - { - return contentSharerGetStreamTypes (uri, mimeTypeFilter); - } - } - -} diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/android/vending/billing/IInAppBillingService.java b/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/android/vending/billing/IInAppBillingService.java deleted file mode 100644 index a40a251ebc..0000000000 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/android/vending/billing/IInAppBillingService.java +++ /dev/null @@ -1,949 +0,0 @@ -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 _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 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 - 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 containing the list of SKUs - * "INAPP_PURCHASE_DATA_LIST" - ArrayList containing the purchase information - * "INAPP_DATA_SIGNATURE_LIST"- ArrayList 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 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 - 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 containing the list of SKUs - * "INAPP_PURCHASE_DATA_LIST" - ArrayList containing the purchase information - * "INAPP_DATA_SIGNATURE_LIST"- ArrayList 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; - } diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java b/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java deleted file mode 100644 index a57dad4cf9..0000000000 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java +++ /dev/null @@ -1,1893 +0,0 @@ -/* - ============================================================================== - - 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. - - ============================================================================== -*/ - -package com.juce.networkgraphicsdemo; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.net.http.SslError; -import android.net.Uri; -import android.os.Bundle; -import android.os.Looper; -import android.os.Handler; -import android.os.Message; -import android.os.ParcelUuid; -import android.os.Environment; -import android.view.*; -import android.view.inputmethod.BaseInputConnection; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputConnection; -import android.view.inputmethod.InputMethodManager; -import android.graphics.*; -import android.text.ClipboardManager; -import android.text.InputType; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.Pair; -import android.webkit.SslErrorHandler; -import android.webkit.WebChromeClient; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import java.lang.Runnable; -import java.lang.ref.WeakReference; -import java.lang.reflect.*; -import java.util.*; -import java.io.*; -import java.net.URL; -import java.net.HttpURLConnection; -import android.media.AudioManager; -import android.Manifest; -import java.util.concurrent.CancellationException; -import java.util.concurrent.Future; -import java.util.concurrent.Executors; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.atomic.*; - - - -//============================================================================== -public class JUCENetworkGraphicsDemo extends Activity -{ - //============================================================================== - static - { - System.loadLibrary ("juce_jni"); - } - - //============================================================================== - public boolean isPermissionDeclaredInManifest (int permissionID) - { - return isPermissionDeclaredInManifest (getAndroidPermissionName (permissionID)); - } - - public boolean isPermissionDeclaredInManifest (String permissionToCheck) - { - try - { - PackageInfo info = getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS); - - if (info.requestedPermissions != null) - for (String permission : info.requestedPermissions) - if (permission.equals (permissionToCheck)) - return true; - } - catch (PackageManager.NameNotFoundException e) - { - Log.d ("JUCE", "isPermissionDeclaredInManifest: PackageManager.NameNotFoundException = " + e.toString()); - } - - Log.d ("JUCE", "isPermissionDeclaredInManifest: could not find requested permission " + permissionToCheck); - return false; - } - - //============================================================================== - // these have to match the values of enum PermissionID in C++ class RuntimePermissions: - private static final int JUCE_PERMISSIONS_RECORD_AUDIO = 1; - private static final int JUCE_PERMISSIONS_BLUETOOTH_MIDI = 2; - private static final int JUCE_PERMISSIONS_READ_EXTERNAL_STORAGE = 3; - private static final int JUCE_PERMISSIONS_WRITE_EXTERNAL_STORAGE = 4; - private static final int JUCE_PERMISSIONS_CAMERA = 5; - - private static String getAndroidPermissionName (int permissionID) - { - switch (permissionID) - { - case JUCE_PERMISSIONS_RECORD_AUDIO: return Manifest.permission.RECORD_AUDIO; - case JUCE_PERMISSIONS_BLUETOOTH_MIDI: return Manifest.permission.ACCESS_COARSE_LOCATION; - // use string value as this is not defined in SDKs < 16 - case JUCE_PERMISSIONS_READ_EXTERNAL_STORAGE: return "android.permission.READ_EXTERNAL_STORAGE"; - case JUCE_PERMISSIONS_WRITE_EXTERNAL_STORAGE: return Manifest.permission.WRITE_EXTERNAL_STORAGE; - case JUCE_PERMISSIONS_CAMERA: return Manifest.permission.CAMERA; - } - - // unknown permission ID! - assert false; - return new String(); - } - - public boolean isPermissionGranted (int permissionID) - { - return getApplicationContext().checkCallingOrSelfPermission (getAndroidPermissionName (permissionID)) == PackageManager.PERMISSION_GRANTED; - } - - private Map permissionCallbackPtrMap; - - public void requestRuntimePermission (int permissionID, long ptrToCallback) - { - String permissionName = getAndroidPermissionName (permissionID); - - if (getApplicationContext().checkCallingOrSelfPermission (permissionName) != PackageManager.PERMISSION_GRANTED) - { - // remember callbackPtr, request permissions, and let onRequestPermissionResult call callback asynchronously - permissionCallbackPtrMap.put (permissionID, ptrToCallback); - requestPermissionsCompat (new String[]{permissionName}, permissionID); - } - else - { - // permissions were already granted before, we can call callback directly - androidRuntimePermissionsCallback (true, ptrToCallback); - } - } - - private native void androidRuntimePermissionsCallback (boolean permissionWasGranted, long ptrToCallback); - - - //============================================================================== - public interface JuceMidiPort - { - boolean isInputPort(); - - // start, stop does nothing on an output port - void start(); - void stop(); - - void close(); - - // send will do nothing on an input port - void sendMidi (byte[] msg, int offset, int count); - } - - //============================================================================== - //============================================================================== - public class BluetoothManager - { - BluetoothManager() - { - } - - public String[] getMidiBluetoothAddresses() - { - String[] bluetoothAddresses = new String[0]; - return bluetoothAddresses; - } - - public String getHumanReadableStringForBluetoothAddress (String address) - { - return address; - } - - public int getBluetoothDeviceStatus (String address) - { - return 0; - } - - public void startStopScan (boolean shouldStart) - { - } - - public boolean pairBluetoothMidiDevice(String address) - { - return false; - } - - public void unpairBluetoothMidiDevice (String address) - { - } - } - - //============================================================================== - public class MidiDeviceManager - { - public MidiDeviceManager() - { - } - - public String[] getJuceAndroidMidiInputDevices() - { - return new String[0]; - } - - public String[] getJuceAndroidMidiOutputDevices() - { - return new String[0]; - } - - public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host) - { - return null; - } - - public JuceMidiPort openMidiOutputPortWithJuceIndex (int index) - { - return null; - } - - public String getInputPortNameForJuceIndex (int index) - { - return ""; - } - - public String getOutputPortNameForJuceIndex (int index) - { - return ""; - } - } - - - public MidiDeviceManager getAndroidMidiDeviceManager() - { - return null; - } - - public BluetoothManager getAndroidBluetoothManager() - { - return null; - } - - //============================================================================== - @Override - public void onCreate (Bundle savedInstanceState) - { - super.onCreate (savedInstanceState); - - isScreenSaverEnabled = true; - hideActionBar(); - viewHolder = new ViewHolder (this); - setContentView (viewHolder); - - setVolumeControlStream (AudioManager.STREAM_MUSIC); - - permissionCallbackPtrMap = new HashMap(); - appPausedResumedListeners = new HashMap(); - } - - @Override - protected void onDestroy() - { - quitApp(); - super.onDestroy(); - - clearDataCache(); - } - - @Override - protected void onPause() - { - suspendApp(); - - Long[] keys = appPausedResumedListeners.keySet().toArray (new Long[appPausedResumedListeners.keySet().size()]); - - for (Long k : keys) - appPausedResumedListeners.get (k).appPaused(); - - try - { - Thread.sleep (1000); // This is a bit of a hack to avoid some hard-to-track-down - // openGL glitches when pausing/resuming apps.. - } catch (InterruptedException e) {} - - super.onPause(); - } - - @Override - protected void onResume() - { - super.onResume(); - resumeApp(); - - Long[] keys = appPausedResumedListeners.keySet().toArray (new Long[appPausedResumedListeners.keySet().size()]); - - for (Long k : keys) - appPausedResumedListeners.get (k).appResumed(); - } - - @Override - public void onConfigurationChanged (Configuration cfg) - { - super.onConfigurationChanged (cfg); - setContentView (viewHolder); - } - - private void callAppLauncher() - { - launchApp (getApplicationInfo().publicSourceDir, - getApplicationInfo().dataDir); - } - - // Need to override this as the default implementation always finishes the activity. - @Override - public void onBackPressed() - { - ComponentPeerView focusedView = getViewWithFocusOrDefaultView(); - - if (focusedView == null) - return; - - focusedView.backButtonPressed(); - } - - private ComponentPeerView getViewWithFocusOrDefaultView() - { - for (int i = 0; i < viewHolder.getChildCount(); ++i) - { - if (viewHolder.getChildAt (i).hasFocus()) - return (ComponentPeerView) viewHolder.getChildAt (i); - } - - if (viewHolder.getChildCount() > 0) - return (ComponentPeerView) viewHolder.getChildAt (0); - - return null; - } - - //============================================================================== - private void hideActionBar() - { - // get "getActionBar" method - java.lang.reflect.Method getActionBarMethod = null; - try - { - getActionBarMethod = this.getClass().getMethod ("getActionBar"); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (getActionBarMethod == null) return; - - // invoke "getActionBar" method - Object actionBar = null; - try - { - actionBar = getActionBarMethod.invoke (this); - } - catch (java.lang.IllegalArgumentException e) { return; } - catch (java.lang.IllegalAccessException e) { return; } - catch (java.lang.reflect.InvocationTargetException e) { return; } - if (actionBar == null) return; - - // get "hide" method - java.lang.reflect.Method actionBarHideMethod = null; - try - { - actionBarHideMethod = actionBar.getClass().getMethod ("hide"); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (actionBarHideMethod == null) return; - - // invoke "hide" method - try - { - actionBarHideMethod.invoke (actionBar); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - - void requestPermissionsCompat (String[] permissions, int requestCode) - { - Method requestPermissionsMethod = null; - try - { - requestPermissionsMethod = this.getClass().getMethod ("requestPermissions", - String[].class, int.class); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (requestPermissionsMethod == null) return; - - try - { - requestPermissionsMethod.invoke (this, permissions, requestCode); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - - //============================================================================== - private native void launchApp (String appFile, String appDataDir); - private native void quitApp(); - private native void suspendApp(); - private native void resumeApp(); - private native void setScreenSize (int screenWidth, int screenHeight, int dpi); - private native void appActivityResult (int requestCode, int resultCode, Intent data); - private native void appNewIntent (Intent intent); - - //============================================================================== - private ViewHolder viewHolder; - private MidiDeviceManager midiDeviceManager = null; - private BluetoothManager bluetoothManager = null; - private boolean isScreenSaverEnabled; - private java.util.Timer keepAliveTimer; - - public final ComponentPeerView createNewView (boolean opaque, long host) - { - ComponentPeerView v = new ComponentPeerView (this, opaque, host); - viewHolder.addView (v); - addAppPausedResumedListener (v, host); - return v; - } - - public final void deleteView (ComponentPeerView view) - { - removeAppPausedResumedListener (view, view.host); - - view.host = 0; - - ViewGroup group = (ViewGroup) (view.getParent()); - - if (group != null) - group.removeView (view); - } - - public final void deleteNativeSurfaceView (NativeSurfaceView view) - { - ViewGroup group = (ViewGroup) (view.getParent()); - - if (group != null) - group.removeView (view); - } - - final class ViewHolder extends ViewGroup - { - public ViewHolder (Context context) - { - super (context); - setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS); - setFocusable (false); - } - - protected final void onLayout (boolean changed, int left, int top, int right, int bottom) - { - setScreenSize (getWidth(), getHeight(), getDPI()); - - if (isFirstResize) - { - isFirstResize = false; - callAppLauncher(); - } - } - - private final int getDPI() - { - DisplayMetrics metrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics (metrics); - return metrics.densityDpi; - } - - private boolean isFirstResize = true; - } - - public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom) - { - canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE); - } - - //============================================================================== - public final void setScreenSaver (boolean enabled) - { - if (isScreenSaverEnabled != enabled) - { - isScreenSaverEnabled = enabled; - - if (keepAliveTimer != null) - { - keepAliveTimer.cancel(); - keepAliveTimer = null; - } - - if (enabled) - { - getWindow().clearFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - else - { - getWindow().addFlags (WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - - // If no user input is received after about 3 seconds, the OS will lower the - // task's priority, so this timer forces it to be kept active. - keepAliveTimer = new java.util.Timer(); - - keepAliveTimer.scheduleAtFixedRate (new TimerTask() - { - @Override - public void run() - { - android.app.Instrumentation instrumentation = new android.app.Instrumentation(); - - try - { - instrumentation.sendKeyDownUpSync (KeyEvent.KEYCODE_UNKNOWN); - } - catch (Exception e) - { - } - } - }, 2000, 2000); - } - } - } - - public final boolean getScreenSaver() - { - return isScreenSaverEnabled; - } - - //============================================================================== - public final String getClipboardContent() - { - ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE); - - CharSequence content = clipboard.getText(); - return content != null ? content.toString() : new String(); - } - - public final void setClipboardContent (String newText) - { - ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE); - clipboard.setText (newText); - } - - //============================================================================== - public final void showMessageBox (String title, String message, final long callback) - { - AlertDialog.Builder builder = new AlertDialog.Builder (this); - builder.setTitle (title) - .setMessage (message) - .setCancelable (true) - .setOnCancelListener (new DialogInterface.OnCancelListener() - { - public void onCancel (DialogInterface dialog) - { - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); - } - }) - .setPositiveButton ("OK", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); - } - }); - - builder.create().show(); - } - - public final void showOkCancelBox (String title, String message, final long callback, - String okButtonText, String cancelButtonText) - { - AlertDialog.Builder builder = new AlertDialog.Builder (this); - builder.setTitle (title) - .setMessage (message) - .setCancelable (true) - .setOnCancelListener (new DialogInterface.OnCancelListener() - { - public void onCancel (DialogInterface dialog) - { - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); - } - }) - .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); - } - }) - .setNegativeButton (cancelButtonText.isEmpty() ? "Cancel" : cancelButtonText, new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); - } - }); - - builder.create().show(); - } - - public final void showYesNoCancelBox (String title, String message, final long callback) - { - AlertDialog.Builder builder = new AlertDialog.Builder (this); - builder.setTitle (title) - .setMessage (message) - .setCancelable (true) - .setOnCancelListener (new DialogInterface.OnCancelListener() - { - public void onCancel (DialogInterface dialog) - { - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); - } - }) - .setPositiveButton ("Yes", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); - } - }) - .setNegativeButton ("No", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 2); - } - }) - .setNeutralButton ("Cancel", new DialogInterface.OnClickListener() - { - public void onClick (DialogInterface dialog, int id) - { - dialog.dismiss(); - JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); - } - }); - - builder.create().show(); - } - - public native void alertDismissed (long callback, int id); - - //============================================================================== - public interface AppPausedResumedListener - { - void appPaused(); - void appResumed(); - } - - private Map appPausedResumedListeners; - - public void addAppPausedResumedListener (AppPausedResumedListener l, long listenerHost) - { - appPausedResumedListeners.put (new Long (listenerHost), l); - } - - public void removeAppPausedResumedListener (AppPausedResumedListener l, long listenerHost) - { - appPausedResumedListeners.remove (new Long (listenerHost)); - } - - //============================================================================== - public final class ComponentPeerView extends ViewGroup - implements View.OnFocusChangeListener, AppPausedResumedListener - { - public ComponentPeerView (Context context, boolean opaque_, long host) - { - super (context); - this.host = host; - setWillNotDraw (false); - opaque = opaque_; - - setFocusable (true); - setFocusableInTouchMode (true); - setOnFocusChangeListener (this); - - // swap red and blue colours to match internal opengl texture format - ColorMatrix colorMatrix = new ColorMatrix(); - - float[] colorTransform = { 0, 0, 1.0f, 0, 0, - 0, 1.0f, 0, 0, 0, - 1.0f, 0, 0, 0, 0, - 0, 0, 0, 1.0f, 0 }; - - colorMatrix.set (colorTransform); - paint.setColorFilter (new ColorMatrixColorFilter (colorMatrix)); - - java.lang.reflect.Method method = null; - - try - { - method = getClass().getMethod ("setLayerType", int.class, Paint.class); - } - catch (SecurityException e) {} - catch (NoSuchMethodException e) {} - - if (method != null) - { - try - { - int layerTypeNone = 0; - method.invoke (this, layerTypeNone, null); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - } - - //============================================================================== - private native void handlePaint (long host, Canvas canvas, Paint paint); - - @Override - public void onDraw (Canvas canvas) - { - if (host == 0) - return; - - handlePaint (host, canvas, paint); - } - - @Override - public boolean isOpaque() - { - return opaque; - } - - private boolean opaque; - private long host; - private Paint paint = new Paint(); - - //============================================================================== - private native void handleMouseDown (long host, int index, float x, float y, long time); - private native void handleMouseDrag (long host, int index, float x, float y, long time); - private native void handleMouseUp (long host, int index, float x, float y, long time); - - @Override - public boolean onTouchEvent (MotionEvent event) - { - if (host == 0) - return false; - - int action = event.getAction(); - long time = event.getEventTime(); - - switch (action & MotionEvent.ACTION_MASK) - { - case MotionEvent.ACTION_DOWN: - handleMouseDown (host, event.getPointerId(0), event.getX(), event.getY(), time); - return true; - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - handleMouseUp (host, event.getPointerId(0), event.getX(), event.getY(), time); - return true; - - case MotionEvent.ACTION_MOVE: - { - int n = event.getPointerCount(); - for (int i = 0; i < n; ++i) - handleMouseDrag (host, event.getPointerId(i), event.getX(i), event.getY(i), time); - - return true; - } - - case MotionEvent.ACTION_POINTER_UP: - { - int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - handleMouseUp (host, event.getPointerId(i), event.getX(i), event.getY(i), time); - return true; - } - - case MotionEvent.ACTION_POINTER_DOWN: - { - int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - handleMouseDown (host, event.getPointerId(i), event.getX(i), event.getY(i), time); - return true; - } - - default: - break; - } - - return false; - } - - //============================================================================== - private native void handleKeyDown (long host, int keycode, int textchar); - private native void handleKeyUp (long host, int keycode, int textchar); - private native void handleBackButton (long host); - private native void handleKeyboardHidden (long host); - - public void showKeyboard (String type) - { - InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE); - - if (imm != null) - { - if (type.length() > 0) - { - imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT); - imm.setInputMethod (getWindowToken(), type); - keyboardDismissListener.startListening(); - } - else - { - imm.hideSoftInputFromWindow (getWindowToken(), 0); - keyboardDismissListener.stopListening(); - } - } - } - - public void backButtonPressed() - { - if (host == 0) - return; - - handleBackButton (host); - } - - @Override - public boolean onKeyDown (int keyCode, KeyEvent event) - { - if (host == 0) - return false; - - switch (keyCode) - { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - return super.onKeyDown (keyCode, event); - case KeyEvent.KEYCODE_BACK: - { - ((Activity) getContext()).onBackPressed(); - return true; - } - - default: - break; - } - - handleKeyDown (host, keyCode, event.getUnicodeChar()); - return true; - } - - @Override - public boolean onKeyUp (int keyCode, KeyEvent event) - { - if (host == 0) - return false; - - handleKeyUp (host, keyCode, event.getUnicodeChar()); - return true; - } - - @Override - public boolean onKeyMultiple (int keyCode, int count, KeyEvent event) - { - if (host == 0) - return false; - - if (keyCode != KeyEvent.KEYCODE_UNKNOWN || event.getAction() != KeyEvent.ACTION_MULTIPLE) - return super.onKeyMultiple (keyCode, count, event); - - if (event.getCharacters() != null) - { - int utf8Char = event.getCharacters().codePointAt (0); - handleKeyDown (host, utf8Char, utf8Char); - return true; - } - - return false; - } - - //============================================================================== - private final class KeyboardDismissListener - { - public KeyboardDismissListener (ComponentPeerView viewToUse) - { - view = viewToUse; - } - - private void startListening() - { - view.getViewTreeObserver().addOnGlobalLayoutListener(viewTreeObserver); - } - - private void stopListening() - { - view.getViewTreeObserver().removeGlobalOnLayoutListener(viewTreeObserver); - } - - private class TreeObserver implements ViewTreeObserver.OnGlobalLayoutListener - { - TreeObserver() - { - keyboardShown = false; - } - - @Override - public void onGlobalLayout() - { - Rect r = new Rect(); - - ViewGroup parentView = (ViewGroup) getParent(); - - if (parentView == null) - return; - - parentView.getWindowVisibleDisplayFrame (r); - - int diff = parentView.getHeight() - (r.bottom - r.top); - - // Arbitrary threshold, surely keyboard would take more than 20 pix. - if (diff < 20 && keyboardShown) - { - keyboardShown = false; - handleKeyboardHidden (view.host); - } - - if (! keyboardShown && diff > 20) - keyboardShown = true; - }; - - private boolean keyboardShown; - }; - - private ComponentPeerView view; - private TreeObserver viewTreeObserver = new TreeObserver(); - } - - private KeyboardDismissListener keyboardDismissListener = new KeyboardDismissListener(this); - - // this is here to make keyboard entry work on a Galaxy Tab2 10.1 - @Override - public InputConnection onCreateInputConnection (EditorInfo outAttrs) - { - outAttrs.actionLabel = ""; - outAttrs.hintText = ""; - outAttrs.initialCapsMode = 0; - outAttrs.initialSelEnd = outAttrs.initialSelStart = -1; - outAttrs.label = ""; - outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI; - outAttrs.inputType = InputType.TYPE_NULL; - - return new BaseInputConnection (this, false); - } - - //============================================================================== - @Override - protected void onSizeChanged (int w, int h, int oldw, int oldh) - { - if (host == 0) - return; - - super.onSizeChanged (w, h, oldw, oldh); - viewSizeChanged (host); - } - - @Override - protected void onLayout (boolean changed, int left, int top, int right, int bottom) - { - for (int i = getChildCount(); --i >= 0;) - requestTransparentRegion (getChildAt (i)); - } - - private native void viewSizeChanged (long host); - - @Override - public void onFocusChange (View v, boolean hasFocus) - { - if (host == 0) - return; - - if (v == this) - focusChanged (host, hasFocus); - } - - private native void focusChanged (long host, boolean hasFocus); - - public void setViewName (String newName) {} - - public void setSystemUiVisibilityCompat (int visibility) - { - Method systemUIVisibilityMethod = null; - try - { - systemUIVisibilityMethod = this.getClass().getMethod ("setSystemUiVisibility", int.class); - } - catch (SecurityException e) { return; } - catch (NoSuchMethodException e) { return; } - if (systemUIVisibilityMethod == null) return; - - try - { - systemUIVisibilityMethod.invoke (this, visibility); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - } - - public boolean isVisible() { return getVisibility() == VISIBLE; } - public void setVisible (boolean b) { setVisibility (b ? VISIBLE : INVISIBLE); } - - public boolean containsPoint (int x, int y) - { - return true; //xxx needs to check overlapping views - } - - //============================================================================== - private native void handleAppPaused (long host); - private native void handleAppResumed (long host); - - @Override - public void appPaused() - { - if (host == 0) - return; - - handleAppPaused (host); - } - - @Override - public void appResumed() - { - if (host == 0) - return; - - // Ensure that navigation/status bar visibility is correctly restored. - handleAppResumed (host); - } - } - - //============================================================================== - public static class NativeSurfaceView extends SurfaceView - implements SurfaceHolder.Callback - { - private long nativeContext = 0; - private boolean forVideo; - - NativeSurfaceView (Context context, long nativeContextPtr, boolean createdForVideo) - { - super (context); - nativeContext = nativeContextPtr; - forVideo = createdForVideo; - } - - public Surface getNativeSurface() - { - Surface retval = null; - - SurfaceHolder holder = getHolder(); - if (holder != null) - retval = holder.getSurface(); - - return retval; - } - - //============================================================================== - @Override - public void surfaceChanged (SurfaceHolder holder, int format, int width, int height) - { - if (forVideo) - surfaceChangedNativeVideo (nativeContext, holder, format, width, height); - else - surfaceChangedNative (nativeContext, holder, format, width, height); - } - - @Override - public void surfaceCreated (SurfaceHolder holder) - { - if (forVideo) - surfaceCreatedNativeVideo (nativeContext, holder); - else - surfaceCreatedNative (nativeContext, holder); - } - - @Override - public void surfaceDestroyed (SurfaceHolder holder) - { - if (forVideo) - surfaceDestroyedNativeVideo (nativeContext, holder); - else - surfaceDestroyedNative (nativeContext, holder); - } - - @Override - protected void dispatchDraw (Canvas canvas) - { - super.dispatchDraw (canvas); - - if (forVideo) - dispatchDrawNativeVideo (nativeContext, canvas); - else - dispatchDrawNative (nativeContext, canvas); - } - - //============================================================================== - @Override - protected void onAttachedToWindow() - { - super.onAttachedToWindow(); - getHolder().addCallback (this); - } - - @Override - protected void onDetachedFromWindow() - { - super.onDetachedFromWindow(); - getHolder().removeCallback (this); - } - - //============================================================================== - private native void dispatchDrawNative (long nativeContextPtr, Canvas canvas); - private native void surfaceCreatedNative (long nativeContextptr, SurfaceHolder holder); - private native void surfaceDestroyedNative (long nativeContextptr, SurfaceHolder holder); - private native void surfaceChangedNative (long nativeContextptr, SurfaceHolder holder, - int format, int width, int height); - - private native void dispatchDrawNativeVideo (long nativeContextPtr, Canvas canvas); - private native void surfaceCreatedNativeVideo (long nativeContextptr, SurfaceHolder holder); - private native void surfaceDestroyedNativeVideo (long nativeContextptr, SurfaceHolder holder); - private native void surfaceChangedNativeVideo (long nativeContextptr, SurfaceHolder holder, - int format, int width, int height); - } - - public NativeSurfaceView createNativeSurfaceView (long nativeSurfacePtr, boolean forVideo) - { - return new NativeSurfaceView (this, nativeSurfacePtr, forVideo); - } - - //============================================================================== - public final int[] renderGlyph (char glyph1, char glyph2, Paint paint, android.graphics.Matrix matrix, Rect bounds) - { - Path p = new Path(); - - char[] str = { glyph1, glyph2 }; - paint.getTextPath (str, 0, (glyph2 != 0 ? 2 : 1), 0.0f, 0.0f, p); - - RectF boundsF = new RectF(); - p.computeBounds (boundsF, true); - matrix.mapRect (boundsF); - - boundsF.roundOut (bounds); - bounds.left--; - bounds.right++; - - final int w = bounds.width(); - final int h = Math.max (1, bounds.height()); - - Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888); - - Canvas c = new Canvas (bm); - matrix.postTranslate (-bounds.left, -bounds.top); - c.setMatrix (matrix); - c.drawPath (p, paint); - - final int sizeNeeded = w * h; - if (cachedRenderArray.length < sizeNeeded) - cachedRenderArray = new int [sizeNeeded]; - - bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h); - bm.recycle(); - return cachedRenderArray; - } - - private int[] cachedRenderArray = new int [256]; - - //============================================================================== - public static class NativeInvocationHandler implements InvocationHandler - { - public NativeInvocationHandler (Activity activityToUse, long nativeContextRef) - { - activity = activityToUse; - nativeContext = nativeContextRef; - } - - public void nativeContextDeleted() - { - nativeContext = 0; - } - - @Override - public void finalize() - { - activity.runOnUiThread (new Runnable() - { - @Override - public void run() - { - if (nativeContext != 0) - dispatchFinalize (nativeContext); - } - }); - } - - @Override - public Object invoke (Object proxy, Method method, Object[] args) throws Throwable - { - return dispatchInvoke (nativeContext, proxy, method, args); - } - - //============================================================================== - Activity activity; - private long nativeContext = 0; - - private native void dispatchFinalize (long nativeContextRef); - private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args); - } - - public InvocationHandler createInvocationHandler (long nativeContextRef) - { - return new NativeInvocationHandler (this, nativeContextRef); - } - - public void invocationHandlerContextDeleted (InvocationHandler handler) - { - ((NativeInvocationHandler) handler).nativeContextDeleted(); - } - - //============================================================================== - public static class HTTPStream - { - public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, - String headersToUse, int timeOutMsToUse, - int[] statusCodeToUse, StringBuffer responseHeadersToUse, - int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException - { - isPost = isPostToUse; - postData = postDataToUse; - headers = headersToUse; - timeOutMs = timeOutMsToUse; - statusCode = statusCodeToUse; - responseHeaders = responseHeadersToUse; - totalLength = -1; - numRedirectsToFollow = numRedirectsToFollowToUse; - httpRequestCmd = httpRequestCmdToUse; - - connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); - } - - private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, - String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException - { - HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); - - try - { - newConnection.setInstanceFollowRedirects (false); - newConnection.setConnectTimeout (timeOutMs); - newConnection.setReadTimeout (timeOutMs); - - // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. - // So convert headers string to an array, with an element for each line - String headerLines[] = headers.split("\\n"); - - // Set request headers - for (int i = 0; i < headerLines.length; ++i) - { - int pos = headerLines[i].indexOf (":"); - - if (pos > 0 && pos < headerLines[i].length()) - { - String field = headerLines[i].substring (0, pos); - String value = headerLines[i].substring (pos + 1); - - if (value.length() > 0) - newConnection.setRequestProperty (field, value); - } - } - - newConnection.setRequestMethod (httpRequestCmd); - - if (isPost) - { - newConnection.setDoOutput (true); - - if (postData != null) - { - OutputStream out = newConnection.getOutputStream(); - out.write(postData); - out.flush(); - } - } - - return newConnection; - } - catch (Throwable e) - { - newConnection.disconnect(); - throw new IOException ("Connection error"); - } - } - - private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException - { - synchronized (createFutureLock) - { - if (hasBeenCancelled.get()) - return null; - - streamFuture = executor.submit (new Callable() - { - @Override - public BufferedInputStream call() throws IOException - { - return new BufferedInputStream (isInput ? connection.getInputStream() - : connection.getErrorStream()); - } - }); - } - - try - { - return streamFuture.get(); - } - catch (InterruptedException e) - { - return null; - } - catch (CancellationException e) - { - return null; - } - } - - public final boolean connect() - { - boolean result = false; - int numFollowedRedirects = 0; - - while (true) - { - result = doConnect(); - - if (! result) - return false; - - if (++numFollowedRedirects > numRedirectsToFollow) - break; - - int status = statusCode[0]; - - if (status == 301 || status == 302 || status == 303 || status == 307) - { - // Assumes only one occurrence of "Location" - int pos1 = responseHeaders.indexOf ("Location:") + 10; - int pos2 = responseHeaders.indexOf ("\n", pos1); - - if (pos2 > pos1) - { - String currentLocation = connection.getURL().toString(); - String newLocation = responseHeaders.substring (pos1, pos2); - - try - { - // Handle newLocation whether it's absolute or relative - URL baseUrl = new URL (currentLocation); - URL newUrl = new URL (baseUrl, newLocation); - String transformedNewLocation = newUrl.toString(); - - if (transformedNewLocation != currentLocation) - { - // Clear responseHeaders before next iteration - responseHeaders.delete (0, responseHeaders.length()); - - synchronized (createStreamLock) - { - if (hasBeenCancelled.get()) - return false; - - connection.disconnect(); - - try - { - connection = createConnection (transformedNewLocation, isPost, - postData, headers, timeOutMs, - httpRequestCmd); - } - catch (Throwable e) - { - return false; - } - } - } - else - { - break; - } - } - catch (Throwable e) - { - return false; - } - } - else - { - break; - } - } - else - { - break; - } - } - - return result; - } - - private final boolean doConnect() - { - synchronized (createStreamLock) - { - if (hasBeenCancelled.get()) - return false; - - try - { - try - { - inputStream = getCancellableStream (true); - } - catch (ExecutionException e) - { - if (connection.getResponseCode() < 400) - { - statusCode[0] = connection.getResponseCode(); - connection.disconnect(); - return false; - } - } - finally - { - statusCode[0] = connection.getResponseCode(); - } - - try - { - if (statusCode[0] >= 400) - inputStream = getCancellableStream (false); - else - inputStream = getCancellableStream (true); - } - catch (ExecutionException e) - {} - - for (java.util.Map.Entry> entry : connection.getHeaderFields().entrySet()) - { - if (entry.getKey() != null && entry.getValue() != null) - { - responseHeaders.append(entry.getKey() + ": " - + android.text.TextUtils.join(",", entry.getValue()) + "\n"); - - if (entry.getKey().compareTo ("Content-Length") == 0) - totalLength = Integer.decode (entry.getValue().get (0)); - } - } - - return true; - } - catch (IOException e) - { - return false; - } - } - } - - static class DisconnectionRunnable implements Runnable - { - public DisconnectionRunnable (HttpURLConnection theConnection, - InputStream theInputStream, - ReentrantLock theCreateStreamLock, - Object theCreateFutureLock, - Future theStreamFuture) - { - connectionToDisconnect = theConnection; - inputStream = theInputStream; - createStreamLock = theCreateStreamLock; - createFutureLock = theCreateFutureLock; - streamFuture = theStreamFuture; - } - - public void run() - { - try - { - if (! createStreamLock.tryLock()) - { - synchronized (createFutureLock) - { - if (streamFuture != null) - streamFuture.cancel (true); - } - - createStreamLock.lock(); - } - - if (connectionToDisconnect != null) - connectionToDisconnect.disconnect(); - - if (inputStream != null) - inputStream.close(); - } - catch (IOException e) - {} - finally - { - createStreamLock.unlock(); - } - } - - private HttpURLConnection connectionToDisconnect; - private InputStream inputStream; - private ReentrantLock createStreamLock; - private Object createFutureLock; - Future streamFuture; - } - - public final void release() - { - DisconnectionRunnable disconnectionRunnable = new DisconnectionRunnable (connection, - inputStream, - createStreamLock, - createFutureLock, - streamFuture); - - synchronized (createStreamLock) - { - hasBeenCancelled.set (true); - - connection = null; - } - - Thread disconnectionThread = new Thread(disconnectionRunnable); - disconnectionThread.start(); - } - - public final int read (byte[] buffer, int numBytes) - { - int num = 0; - - try - { - synchronized (createStreamLock) - { - if (inputStream != null) - num = inputStream.read (buffer, 0, numBytes); - } - } - catch (IOException e) - {} - - if (num > 0) - position += num; - - return num; - } - - public final long getPosition() { return position; } - public final long getTotalLength() { return totalLength; } - public final boolean isExhausted() { return false; } - public final boolean setPosition (long newPos) { return false; } - - private boolean isPost; - private byte[] postData; - private String headers; - private int timeOutMs; - String httpRequestCmd; - private HttpURLConnection connection; - private int[] statusCode; - private StringBuffer responseHeaders; - private int totalLength; - private int numRedirectsToFollow; - private InputStream inputStream; - private long position; - private final ReentrantLock createStreamLock = new ReentrantLock(); - private final Object createFutureLock = new Object(); - private AtomicBoolean hasBeenCancelled = new AtomicBoolean(); - - private final ExecutorService executor = Executors.newCachedThreadPool (Executors.defaultThreadFactory()); - Future streamFuture; - } - - public static final HTTPStream createHTTPStream (String address, boolean isPost, byte[] postData, - String headers, int timeOutMs, int[] statusCode, - StringBuffer responseHeaders, int numRedirectsToFollow, - String httpRequestCmd) - { - // timeout parameter of zero for HttpUrlConnection is a blocking connect (negative value for juce::URL) - if (timeOutMs < 0) - timeOutMs = 0; - else if (timeOutMs == 0) - timeOutMs = 30000; - - for (;;) - { - try - { - HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, - timeOutMs, statusCode, responseHeaders, - numRedirectsToFollow, httpRequestCmd); - - return httpStream; - } - catch (Throwable e) {} - - return null; - } - } - - public final void launchURL (String url) - { - startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url))); - } - - private native boolean webViewPageLoadStarted (long host, WebView view, String url); - private native void webViewPageLoadFinished (long host, WebView view, String url); - private native void webViewReceivedSslError (long host, WebView view, SslErrorHandler handler, SslError error); - private native void webViewCloseWindowRequest (long host, WebView view); - private native void webViewCreateWindowRequest (long host, WebView view); - - //============================================================================== - public class JuceWebViewClient extends WebViewClient - { - public JuceWebViewClient (long hostToUse) - { - host = hostToUse; - } - - public void hostDeleted() - { - synchronized (hostLock) - { - host = 0; - } - } - - @Override - public void onPageFinished (WebView view, String url) - { - if (host == 0) - return; - - webViewPageLoadFinished (host, view, url); - } - - @Override - public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) - { - if (host == 0) - return; - - webViewReceivedSslError (host, view, handler, error); - } - - @Override - public void onPageStarted (WebView view, String url, Bitmap favicon) - { - if (host != 0) - webViewPageLoadStarted (host, view, url); - } - - private long host; - private final Object hostLock = new Object(); - } - - public class JuceWebChromeClient extends WebChromeClient - { - public JuceWebChromeClient (long hostToUse) - { - host = hostToUse; - } - - @Override - public void onCloseWindow (WebView window) - { - webViewCloseWindowRequest (host, window); - } - - @Override - public boolean onCreateWindow (WebView view, boolean isDialog, - boolean isUserGesture, Message resultMsg) - { - webViewCreateWindowRequest (host, view); - return false; - } - - private long host; - private final Object hostLock = new Object(); - } - - - //============================================================================== - public static final String getLocaleValue (boolean isRegion) - { - java.util.Locale locale = java.util.Locale.getDefault(); - - return isRegion ? locale.getCountry() - : locale.getLanguage(); - } - - private static final String getFileLocation (String type) - { - return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); - } - - public static final String getDocumentsFolder() - { - if (getAndroidSDKVersion() >= 19) - return getFileLocation ("Documents"); - - return Environment.getDataDirectory().getAbsolutePath(); - } - - public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } - public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } - public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } - public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); } - - //============================================================================== - @Override - protected void onActivityResult (int requestCode, int resultCode, Intent data) - { - appActivityResult (requestCode, resultCode, data); - } - - @Override - protected void onNewIntent (Intent intent) - { - super.onNewIntent(intent); - setIntent(intent); - - appNewIntent (intent); - } - - //============================================================================== - public final Typeface getTypeFaceFromAsset (String assetName) - { - try - { - return Typeface.createFromAsset (this.getResources().getAssets(), assetName); - } - catch (Throwable e) {} - - return null; - } - - final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); - - public static String bytesToHex (byte[] bytes) - { - char[] hexChars = new char[bytes.length * 2]; - - for (int j = 0; j < bytes.length; ++j) - { - int v = bytes[j] & 0xff; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0f]; - } - - return new String (hexChars); - } - - final private java.util.Map dataCache = new java.util.HashMap(); - - synchronized private final File getDataCacheFile (byte[] data) - { - try - { - java.security.MessageDigest digest = java.security.MessageDigest.getInstance ("MD5"); - digest.update (data); - - String key = bytesToHex (digest.digest()); - - if (dataCache.containsKey (key)) - return (File) dataCache.get (key); - - File f = new File (this.getCacheDir(), "bindata_" + key); - f.delete(); - FileOutputStream os = new FileOutputStream (f); - os.write (data, 0, data.length); - dataCache.put (key, f); - return f; - } - catch (Throwable e) {} - - return null; - } - - private final void clearDataCache() - { - java.util.Iterator it = dataCache.values().iterator(); - - while (it.hasNext()) - { - File f = (File) it.next(); - f.delete(); - } - } - - public final Typeface getTypeFaceFromByteArray (byte[] data) - { - try - { - File f = getDataCacheFile (data); - - if (f != null) - return Typeface.createFromFile (f); - } - catch (Exception e) - { - Log.e ("JUCE", e.toString()); - } - - return null; - } - - public static final int getAndroidSDKVersion() - { - return android.os.Build.VERSION.SDK_INT; - } - - public final String audioManagerGetProperty (String property) - { - Object obj = getSystemService (AUDIO_SERVICE); - if (obj == null) - return null; - - java.lang.reflect.Method method; - - try - { - method = obj.getClass().getMethod ("getProperty", String.class); - } - catch (SecurityException e) { return null; } - catch (NoSuchMethodException e) { return null; } - - if (method == null) - return null; - - try - { - return (String) method.invoke (obj, property); - } - catch (java.lang.IllegalArgumentException e) {} - catch (java.lang.IllegalAccessException e) {} - catch (java.lang.reflect.InvocationTargetException e) {} - - return null; - } - - public final boolean hasSystemFeature (String property) - { - return getPackageManager().hasSystemFeature (property); - } -} diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/SharingContentProvider.java b/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/SharingContentProvider.java deleted file mode 100644 index 516c527b8d..0000000000 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/SharingContentProvider.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - ============================================================================== - - 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. - - ============================================================================== -*/ - -package com.juce.networkgraphicsdemo; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.res.AssetFileDescriptor; -import android.content.res.Resources; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.net.Uri; -import android.os.FileObserver; -import android.os.ParcelFileDescriptor; -import java.lang.String; - -public final class SharingContentProvider extends ContentProvider -{ - private Object lock = new Object(); - - private native void contentSharerFileObserverEvent (long host, int event, String path); - - private native Cursor contentSharerQuery (Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder); - - private native void contentSharerCursorClosed (long host); - - private native AssetFileDescriptor contentSharerOpenFile (Uri uri, String mode); - private native String[] contentSharerGetStreamTypes (Uri uri, String mimeTypeFilter); - - public final class ProviderFileObserver extends FileObserver - { - public ProviderFileObserver (long hostToUse, String path, int mask) - { - super (path, mask); - - host = hostToUse; - } - - public void onEvent (int event, String path) - { - contentSharerFileObserverEvent (host, event, path); - } - - private long host; - } - - public final class ProviderCursor extends MatrixCursor - { - ProviderCursor (long hostToUse, String[] columnNames) - { - super (columnNames); - - host = hostToUse; - } - - @Override - public void close() - { - super.close(); - - contentSharerCursorClosed (host); - } - - private long host; - } - - @Override - public boolean onCreate() - { - return true; - } - - @Override - public Cursor query (Uri url, String[] projection, String selection, - String[] selectionArgs, String sortOrder) - { - synchronized (lock) - { - return contentSharerQuery (url, projection, selection, selectionArgs, sortOrder); - } - } - - @Override - public Uri insert (Uri uri, ContentValues values) - { - return null; - } - - @Override - public int update (Uri uri, ContentValues values, String selection, - String[] selectionArgs) - { - return 0; - } - - @Override - public int delete (Uri uri, String selection, String[] selectionArgs) - { - return 0; - } - - @Override - public String getType (Uri uri) - { - return null; - } - - @Override - public AssetFileDescriptor openAssetFile (Uri uri, String mode) - { - synchronized (lock) - { - return contentSharerOpenFile (uri, mode); - } - } - - @Override - public ParcelFileDescriptor openFile (Uri uri, String mode) - { - synchronized (lock) - { - AssetFileDescriptor result = contentSharerOpenFile (uri, mode); - - if (result != null) - return result.getParcelFileDescriptor(); - - return null; - } - } - -}