Merge pull request #31709 from akien-mga/android-fix-thirdparty
Android: Fix another regression with Secure.ANDROID_ID, and fix formatting and documentation of thirdparty code
This commit is contained in:
commit
f38c64e8b1
@ -86,6 +86,9 @@ do
|
|||||||
if grep -q "thirdparty" <<< $file; then
|
if grep -q "thirdparty" <<< $file; then
|
||||||
continue;
|
continue;
|
||||||
fi
|
fi
|
||||||
|
if grep -q "platform/android/java/src/com" <<< $file; then
|
||||||
|
continue;
|
||||||
|
fi
|
||||||
|
|
||||||
# ignore file if we do check for file extensions and the file
|
# ignore file if we do check for file extensions and the file
|
||||||
# does not match any of the extensions specified in $FILE_EXTS
|
# does not match any of the extensions specified in $FILE_EXTS
|
||||||
|
@ -11,7 +11,7 @@ else
|
|||||||
RANGE=HEAD
|
RANGE=HEAD
|
||||||
fi
|
fi
|
||||||
|
|
||||||
FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$")
|
FILES=$(git diff-tree --no-commit-id --name-only -r $RANGE | grep -v thirdparty/ | grep -v platform/android/java/src/com/ | grep -E "\.(c|h|cpp|hpp|cc|hh|cxx|m|mm|inc|java|glsl)$")
|
||||||
echo "Checking files:\n$FILES"
|
echo "Checking files:\n$FILES"
|
||||||
|
|
||||||
# create a random filename to store our generated patch
|
# create a random filename to store our generated patch
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
# Third party libraries
|
|
||||||
|
|
||||||
|
|
||||||
## Google's vending library
|
|
||||||
|
|
||||||
- Upstream: https://github.com/google/play-licensing/tree/master/lvl_library/src/main/java/com/google/android/vending
|
|
||||||
- Version: git (eb57657, 2018) with modifications
|
|
||||||
- License: Apache 2.0
|
|
||||||
|
|
||||||
Overwrite all files under `com/google/android/vending`
|
|
||||||
|
|
||||||
### Modify some files to avoid compile error and lint warning
|
|
||||||
|
|
||||||
#### com/google/android/vending/licensing/util/Base64.java
|
|
||||||
```
|
|
||||||
@@ -338,7 +338,8 @@ public class Base64 {
|
|
||||||
e += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
- assert (e == outBuff.length);
|
|
||||||
+ if (BuildConfig.DEBUG && e != outBuff.length)
|
|
||||||
+ throw new RuntimeException();
|
|
||||||
return outBuff;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### com/google/android/vending/licensing/LicenseChecker.java
|
|
||||||
```
|
|
||||||
@@ -29,8 +29,8 @@ import android.os.RemoteException;
|
|
||||||
import android.provider.Settings.Secure;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
-import com.android.vending.licensing.ILicenseResultListener;
|
|
||||||
-import com.android.vending.licensing.ILicensingService;
|
|
||||||
+import com.google.android.vending.licensing.ILicenseResultListener;
|
|
||||||
+import com.google.android.vending.licensing.ILicensingService;
|
|
||||||
import com.google.android.vending.licensing.util.Base64;
|
|
||||||
import com.google.android.vending.licensing.util.Base64DecoderException;
|
|
||||||
```
|
|
||||||
```
|
|
||||||
@@ -287,13 +287,15 @@ public class LicenseChecker implements ServiceConnection {
|
|
||||||
if (logResponse) {
|
|
||||||
- String android_id = Secure.getString(mContext.getContentResolver(),
|
|
||||||
- Secure.ANDROID_ID);
|
|
||||||
+ String android_id = Secure.ANDROID_ID;
|
|
||||||
Date date = new Date();
|
|
||||||
```
|
|
39
platform/android/java/THIRDPARTY.md
Normal file
39
platform/android/java/THIRDPARTY.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Third-party libraries
|
||||||
|
|
||||||
|
This file list third-party libraries used in the Android source folder,
|
||||||
|
with their provenance and, when relevant, modifications made to those files.
|
||||||
|
|
||||||
|
## com.android.vending.billing
|
||||||
|
|
||||||
|
- Upstream: https://github.com/googlesamples/android-play-billing/tree/master/TrivialDrive/app/src/main
|
||||||
|
- Version: git (7a94c69, 2019)
|
||||||
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
Overwrite the file `aidl/com/android/vending/billing/IInAppBillingService.aidl`.
|
||||||
|
|
||||||
|
## com.google.android.vending.expansion.downloader
|
||||||
|
|
||||||
|
- Upstream: https://github.com/google/play-apk-expansion/tree/master/apkx_library
|
||||||
|
- Version: git (9ecf54e, 2017)
|
||||||
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
Overwrite all files under:
|
||||||
|
|
||||||
|
- `src/com/google/android/vending/expansion/downloader`
|
||||||
|
|
||||||
|
Some files have been modified for yet unclear reasons.
|
||||||
|
See the `patches/com.google.android.vending.expansion.downloader.patch` file.
|
||||||
|
|
||||||
|
## com.google.android.vending.licensing
|
||||||
|
|
||||||
|
- Upstream: https://github.com/google/play-licensing/tree/master/lvl_library/
|
||||||
|
- Version: git (eb57657, 2018) with modifications
|
||||||
|
- License: Apache 2.0
|
||||||
|
|
||||||
|
Overwrite all files under:
|
||||||
|
|
||||||
|
- `aidl/com/android/vending/licensing`
|
||||||
|
- `src/com/google/android/vending/licensing`
|
||||||
|
|
||||||
|
Some files have been modified to silence linter errors or fix downstream issues.
|
||||||
|
See the `patches/com.google.android.vending.licensing.patch` file.
|
@ -34,10 +34,11 @@ import android.os.Bundle;
|
|||||||
*
|
*
|
||||||
* All calls will give a response code with the following possible values
|
* All calls will give a response code with the following possible values
|
||||||
* RESULT_OK = 0 - success
|
* RESULT_OK = 0 - success
|
||||||
* RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog
|
* RESULT_USER_CANCELED = 1 - User pressed back or canceled a dialog
|
||||||
* RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested
|
* RESULT_SERVICE_UNAVAILABLE = 2 - The network connection is down
|
||||||
* RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase
|
* RESULT_BILLING_UNAVAILABLE = 3 - This billing API version is not supported for the type requested
|
||||||
* RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API
|
* 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_ERROR = 6 - Fatal error during the API action
|
||||||
* RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
|
* 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
|
* RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
|
||||||
@ -46,11 +47,11 @@ interface IInAppBillingService {
|
|||||||
/**
|
/**
|
||||||
* Checks support for the requested billing API version, package and in-app type.
|
* Checks support for the requested billing API version, package and in-app type.
|
||||||
* Minimum API version supported by this interface is 3.
|
* Minimum API version supported by this interface is 3.
|
||||||
* @param apiVersion the billing version which the app is using
|
* @param apiVersion billing API version that the app is using
|
||||||
* @param packageName the package name of the calling app
|
* @param packageName the package name of the calling app
|
||||||
* @param type type of the in-app item being purchased "inapp" for one-time purchases
|
* @param type type of the in-app item being purchased ("inapp" for one-time purchases
|
||||||
* and "subs" for subscription.
|
* and "subs" for subscriptions)
|
||||||
* @return RESULT_OK(0) on success, corresponding result code on failures
|
* @return RESULT_OK(0) on success and appropriate response code on failures.
|
||||||
*/
|
*/
|
||||||
int isBillingSupported(int apiVersion, String packageName, String type);
|
int isBillingSupported(int apiVersion, String packageName, String type);
|
||||||
|
|
||||||
@ -59,16 +60,23 @@ interface IInAppBillingService {
|
|||||||
* Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
|
* 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.
|
* with a list JSON strings containing the productId, price, title and description.
|
||||||
* This API can be called with a maximum of 20 SKUs.
|
* This API can be called with a maximum of 20 SKUs.
|
||||||
* @param apiVersion billing API version that the Third-party is using
|
* @param apiVersion billing API version that the app is using
|
||||||
* @param packageName the package name of the calling app
|
* @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"
|
* @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
|
||||||
* @return Bundle containing the following key-value pairs
|
* @return Bundle containing the following key-value pairs
|
||||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
|
||||||
* failure as listed above.
|
* on failures.
|
||||||
* "DETAILS_LIST" with a StringArrayList containing purchase information
|
* "DETAILS_LIST" with a StringArrayList containing purchase information
|
||||||
* in JSON format similar to:
|
* in JSON format similar to:
|
||||||
* '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00",
|
* '{ "productId" : "exampleSku",
|
||||||
* "title : "Example Title", "description" : "This is an example description" }'
|
* "type" : "inapp",
|
||||||
|
* "price" : "$5.00",
|
||||||
|
* "price_currency": "USD",
|
||||||
|
* "price_amount_micros": 5000000,
|
||||||
|
* "title : "Example Title",
|
||||||
|
* "description" : "This is an example description" }'
|
||||||
*/
|
*/
|
||||||
Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
|
Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
|
||||||
|
|
||||||
@ -78,19 +86,19 @@ interface IInAppBillingService {
|
|||||||
* @param apiVersion billing API version that the app is using
|
* @param apiVersion billing API version that the app is using
|
||||||
* @param packageName package name of the calling app
|
* @param packageName package name of the calling app
|
||||||
* @param sku the SKU of the in-app item as published in the developer console
|
* @param sku the SKU of the in-app item as published in the developer console
|
||||||
* @param type the type of the in-app item ("inapp" for one-time purchases
|
* @param type of the in-app item being purchased ("inapp" for one-time purchases
|
||||||
* and "subs" for subscription).
|
* and "subs" for subscriptions)
|
||||||
* @param developerPayload optional argument to be sent back with the purchase information
|
* @param developerPayload optional argument to be sent back with the purchase information
|
||||||
* @return Bundle containing the following key-value pairs
|
* @return Bundle containing the following key-value pairs
|
||||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
|
||||||
* failure as listed above.
|
* on failures.
|
||||||
* "BUY_INTENT" - PendingIntent to start the purchase flow
|
* "BUY_INTENT" - PendingIntent to start the purchase flow
|
||||||
*
|
*
|
||||||
* The Pending intent should be launched with startIntentSenderForResult. When 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.
|
* 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
|
* If the purchase is successful, the result data will contain the following key-value pairs
|
||||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
|
||||||
* failure as listed above.
|
* codes on failures.
|
||||||
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
|
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
|
||||||
* '{"orderId":"12999763169054705758.1371079406387615",
|
* '{"orderId":"12999763169054705758.1371079406387615",
|
||||||
* "packageName":"com.example.app",
|
* "packageName":"com.example.app",
|
||||||
@ -100,7 +108,6 @@ interface IInAppBillingService {
|
|||||||
* "developerPayload":"example developer payload" }'
|
* "developerPayload":"example developer payload" }'
|
||||||
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
|
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
|
||||||
* was signed with the private key of the developer
|
* was signed with the private key of the developer
|
||||||
* TODO: change this to app-specific keys.
|
|
||||||
*/
|
*/
|
||||||
Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
|
Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
|
||||||
String developerPayload);
|
String developerPayload);
|
||||||
@ -112,15 +119,15 @@ interface IInAppBillingService {
|
|||||||
* V1 and V2 that have not been consumed.
|
* V1 and V2 that have not been consumed.
|
||||||
* @param apiVersion billing API version that the app is using
|
* @param apiVersion billing API version that the app is using
|
||||||
* @param packageName package name of the calling app
|
* @param packageName package name of the calling app
|
||||||
* @param type the type of the in-app items being requested
|
* @param type of the in-app items being requested ("inapp" for one-time purchases
|
||||||
* ("inapp" for one-time purchases and "subs" for subscription).
|
* and "subs" for subscriptions)
|
||||||
* @param continuationToken to be set as null for the first call, if the number of owned
|
* @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.
|
* 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
|
* This method can be called again with the continuation token to get the next set of
|
||||||
* owned skus.
|
* owned skus.
|
||||||
* @return Bundle containing the following key-value pairs
|
* @return Bundle containing the following key-value pairs
|
||||||
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
|
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
|
||||||
* failure as listed above.
|
on failures.
|
||||||
* "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
|
* "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
|
||||||
* "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
|
* "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
|
||||||
* "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
|
* "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
|
||||||
@ -138,7 +145,137 @@ interface IInAppBillingService {
|
|||||||
* @param packageName package name of the calling app
|
* @param packageName package name of the calling app
|
||||||
* @param purchaseToken token in the purchase information JSON that identifies the purchase
|
* @param purchaseToken token in the purchase information JSON that identifies the purchase
|
||||||
* to be consumed
|
* to be consumed
|
||||||
* @return 0 if consumption succeeded. Appropriate error values for failures.
|
* @return RESULT_OK(0) if consumption succeeded, appropriate response codes on failures.
|
||||||
*/
|
*/
|
||||||
int consumePurchase(int apiVersion, String packageName, String purchaseToken);
|
int consumePurchase(int apiVersion, String packageName, String purchaseToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This API is currently under development.
|
||||||
|
*/
|
||||||
|
int stub(int apiVersion, String packageName, String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
Bundle getBuyIntentToReplaceSkus(int apiVersion, String packageName,
|
||||||
|
in List<String> oldSkus, String newSku, String type, String developerPayload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pending intent to launch the purchase flow for an in-app item. This method is
|
||||||
|
* a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams}
|
||||||
|
* parameter. This parameter is a Bundle of optional keys and values that affect the
|
||||||
|
* operation of the method.
|
||||||
|
* @param apiVersion billing API version that the app is using, must be 6 or later
|
||||||
|
* @param packageName package name of the calling app
|
||||||
|
* @param sku the SKU of the in-app item as published in the developer console
|
||||||
|
* @param type of the in-app item being purchased ("inapp" for one-time purchases
|
||||||
|
* and "subs" for subscriptions)
|
||||||
|
* @param developerPayload optional argument to be sent back with the purchase information
|
||||||
|
* @extraParams a Bundle with the following optional keys:
|
||||||
|
* "skusToReplace" - List<String> - an optional list of SKUs that the user is
|
||||||
|
* upgrading or downgrading from.
|
||||||
|
* Pass this field if the purchase is upgrading or downgrading
|
||||||
|
* existing subscriptions.
|
||||||
|
* The specified SKUs are replaced with the SKUs that the user is
|
||||||
|
* purchasing. Google Play replaces the specified SKUs at the start of
|
||||||
|
* the next billing cycle.
|
||||||
|
* "replaceSkusProration" - Boolean - whether the user should be credited for any unused
|
||||||
|
* subscription time on the SKUs they are upgrading or downgrading.
|
||||||
|
* If you set this field to true, Google Play swaps out the old SKUs
|
||||||
|
* and credits the user with the unused value of their subscription
|
||||||
|
* time on a pro-rated basis.
|
||||||
|
* Google Play applies this credit to the new subscription, and does
|
||||||
|
* not begin billing the user for the new subscription until after
|
||||||
|
* the credit is used up.
|
||||||
|
* If you set this field to false, the user does not receive credit for
|
||||||
|
* any unused subscription time and the recurrence date does not
|
||||||
|
* change.
|
||||||
|
* Default value is true. Ignored if you do not pass skusToReplace.
|
||||||
|
* "accountId" - String - an optional obfuscated string that is uniquely
|
||||||
|
* associated with the user's account in your app.
|
||||||
|
* If you pass this value, Google Play can use it to detect irregular
|
||||||
|
* activity, such as many devices making purchases on the same
|
||||||
|
* account in a short period of time.
|
||||||
|
* Do not use the developer ID or the user's Google ID for this field.
|
||||||
|
* In addition, this field should not contain the user's ID in
|
||||||
|
* cleartext.
|
||||||
|
* We recommend that you use a one-way hash to generate a string from
|
||||||
|
* the user's ID, and store the hashed string in this field.
|
||||||
|
* "vr" - Boolean - an optional flag indicating whether the returned intent
|
||||||
|
* should start a VR purchase flow. The apiVersion must also be 7 or
|
||||||
|
* later to use this flag.
|
||||||
|
*/
|
||||||
|
Bundle getBuyIntentExtraParams(int apiVersion, String packageName, String sku,
|
||||||
|
String type, String developerPayload, in Bundle extraParams);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the most recent purchase made by the user for each SKU, even if that purchase is
|
||||||
|
* expired, canceled, or consumed.
|
||||||
|
* @param apiVersion billing API version that the app is using, must be 6 or later
|
||||||
|
* @param packageName package name of the calling app
|
||||||
|
* @param type of the in-app items being requested ("inapp" for one-time purchases
|
||||||
|
* and "subs" for subscriptions)
|
||||||
|
* @param continuationToken to be set as null for the first call, if the number of owned
|
||||||
|
* skus is too large, a continuationToken is returned in the response bundle.
|
||||||
|
* This method can be called again with the continuation token to get the next set of
|
||||||
|
* owned skus.
|
||||||
|
* @param extraParams a Bundle with extra params that would be appended into http request
|
||||||
|
* query string. Not used at this moment. Reserved for future functionality.
|
||||||
|
* @return Bundle containing the following key-value pairs
|
||||||
|
* "RESPONSE_CODE" with int value: RESULT_OK(0) if success,
|
||||||
|
* {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures.
|
||||||
|
*
|
||||||
|
* "INAPP_PURCHASE_ITEM_LIST" - ArrayList<String> containing the list of SKUs
|
||||||
|
* "INAPP_PURCHASE_DATA_LIST" - ArrayList<String> containing the purchase information
|
||||||
|
* "INAPP_DATA_SIGNATURE_LIST"- ArrayList<String> containing the signatures
|
||||||
|
* of the purchase information
|
||||||
|
* "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
|
||||||
|
* next set of in-app purchases. Only set if the
|
||||||
|
* user has more owned skus than the current list.
|
||||||
|
*/
|
||||||
|
Bundle getPurchaseHistory(int apiVersion, String packageName, String type,
|
||||||
|
String continuationToken, in Bundle extraParams);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is a variant of {@link #isBillingSupported}} that takes an additional
|
||||||
|
* {@code extraParams} parameter.
|
||||||
|
* @param apiVersion billing API version that the app is using, must be 7 or later
|
||||||
|
* @param packageName package name of the calling app
|
||||||
|
* @param type of the in-app item being purchased ("inapp" for one-time purchases and "subs"
|
||||||
|
* for subscriptions)
|
||||||
|
* @param extraParams a Bundle with the following optional keys:
|
||||||
|
* "vr" - Boolean - an optional flag to indicate whether {link #getBuyIntentExtraParams}
|
||||||
|
* supports returning a VR purchase flow.
|
||||||
|
* @return RESULT_OK(0) on success and appropriate response code on failures.
|
||||||
|
*/
|
||||||
|
int isBillingSupportedExtraParams(int apiVersion, String packageName, String type,
|
||||||
|
in Bundle extraParams);
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package com.android.vending.licensing;
|
package com.android.vending.licensing;
|
||||||
|
|
||||||
// Android library projects do not yet support AIDL, so this has been
|
|
||||||
// precompiled into the src directory.
|
|
||||||
oneway interface ILicenseResultListener {
|
oneway interface ILicenseResultListener {
|
||||||
void verifyLicense(int responseCode, String signedData, String signature);
|
void verifyLicense(int responseCode, String signedData, String signature);
|
||||||
}
|
}
|
@ -18,8 +18,6 @@ package com.android.vending.licensing;
|
|||||||
|
|
||||||
import com.android.vending.licensing.ILicenseResultListener;
|
import com.android.vending.licensing.ILicenseResultListener;
|
||||||
|
|
||||||
// Android library projects do not yet support AIDL, so this has been
|
|
||||||
// precompiled into the src directory.
|
|
||||||
oneway interface ILicensingService {
|
oneway interface ILicensingService {
|
||||||
void checkLicense(long nonce, String packageName, in ILicenseResultListener listener);
|
void checkLicense(long nonce, String packageName, in ILicenseResultListener listener);
|
||||||
}
|
}
|
@ -0,0 +1,300 @@
|
|||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
|
||||||
|
index ad6ea0de6..452c7d148 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
|
||||||
|
@@ -32,6 +32,9 @@ import android.os.Messenger;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
+// -- GODOT start --
|
||||||
|
+import java.lang.ref.WeakReference;
|
||||||
|
+// -- GODOT end --
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -118,29 +121,46 @@ public class DownloaderClientMarshaller {
|
||||||
|
/**
|
||||||
|
* Target we publish for clients to send messages to IncomingHandler.
|
||||||
|
*/
|
||||||
|
- final Messenger mMessenger = new Messenger(new Handler() {
|
||||||
|
+ // -- GODOT start --
|
||||||
|
+ private final MessengerHandlerClient mMsgHandler = new MessengerHandlerClient(this);
|
||||||
|
+ final Messenger mMessenger = new Messenger(mMsgHandler);
|
||||||
|
+
|
||||||
|
+ private static class MessengerHandlerClient extends Handler {
|
||||||
|
+ private final WeakReference<Stub> mDownloader;
|
||||||
|
+ public MessengerHandlerClient(Stub downloader) {
|
||||||
|
+ mDownloader = new WeakReference<>(downloader);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
- switch (msg.what) {
|
||||||
|
- case MSG_ONDOWNLOADPROGRESS:
|
||||||
|
- Bundle bun = msg.getData();
|
||||||
|
- if ( null != mContext ) {
|
||||||
|
- bun.setClassLoader(mContext.getClassLoader());
|
||||||
|
- DownloadProgressInfo dpi = (DownloadProgressInfo) msg.getData()
|
||||||
|
- .getParcelable(PARAM_PROGRESS);
|
||||||
|
- mItf.onDownloadProgress(dpi);
|
||||||
|
- }
|
||||||
|
- break;
|
||||||
|
- case MSG_ONDOWNLOADSTATE_CHANGED:
|
||||||
|
- mItf.onDownloadStateChanged(msg.getData().getInt(PARAM_NEW_STATE));
|
||||||
|
- break;
|
||||||
|
- case MSG_ONSERVICECONNECTED:
|
||||||
|
- mItf.onServiceConnected(
|
||||||
|
- (Messenger) msg.getData().getParcelable(PARAM_MESSENGER));
|
||||||
|
- break;
|
||||||
|
+ Stub downloader = mDownloader.get();
|
||||||
|
+ if (downloader != null) {
|
||||||
|
+ downloader.handleMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- });
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void handleMessage(Message msg) {
|
||||||
|
+ switch (msg.what) {
|
||||||
|
+ case MSG_ONDOWNLOADPROGRESS:
|
||||||
|
+ Bundle bun = msg.getData();
|
||||||
|
+ if (null != mContext) {
|
||||||
|
+ bun.setClassLoader(mContext.getClassLoader());
|
||||||
|
+ DownloadProgressInfo dpi = (DownloadProgressInfo)msg.getData()
|
||||||
|
+ .getParcelable(PARAM_PROGRESS);
|
||||||
|
+ mItf.onDownloadProgress(dpi);
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ case MSG_ONDOWNLOADSTATE_CHANGED:
|
||||||
|
+ mItf.onDownloadStateChanged(msg.getData().getInt(PARAM_NEW_STATE));
|
||||||
|
+ break;
|
||||||
|
+ case MSG_ONSERVICECONNECTED:
|
||||||
|
+ mItf.onServiceConnected(
|
||||||
|
+ (Messenger)msg.getData().getParcelable(PARAM_MESSENGER));
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // -- GODOT end --
|
||||||
|
|
||||||
|
public Stub(IDownloaderClient itf, Class<?> downloaderService) {
|
||||||
|
mItf = itf;
|
||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
|
||||||
|
index 979352299..3771d19c9 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
|
||||||
|
@@ -25,6 +25,9 @@ import android.os.Message;
|
||||||
|
import android.os.Messenger;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
+// -- GODOT start --
|
||||||
|
+import java.lang.ref.WeakReference;
|
||||||
|
+// -- GODOT end --
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -108,32 +111,49 @@ public class DownloaderServiceMarshaller {
|
||||||
|
|
||||||
|
private static class Stub implements IStub {
|
||||||
|
private IDownloaderService mItf = null;
|
||||||
|
- final Messenger mMessenger = new Messenger(new Handler() {
|
||||||
|
+ // -- GODOT start --
|
||||||
|
+ private final MessengerHandlerServer mMsgHandler = new MessengerHandlerServer(this);
|
||||||
|
+ final Messenger mMessenger = new Messenger(mMsgHandler);
|
||||||
|
+
|
||||||
|
+ private static class MessengerHandlerServer extends Handler {
|
||||||
|
+ private final WeakReference<Stub> mDownloader;
|
||||||
|
+ public MessengerHandlerServer(Stub downloader) {
|
||||||
|
+ mDownloader = new WeakReference<>(downloader);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
- switch (msg.what) {
|
||||||
|
- case MSG_REQUEST_ABORT_DOWNLOAD:
|
||||||
|
- mItf.requestAbortDownload();
|
||||||
|
- break;
|
||||||
|
- case MSG_REQUEST_CONTINUE_DOWNLOAD:
|
||||||
|
- mItf.requestContinueDownload();
|
||||||
|
- break;
|
||||||
|
- case MSG_REQUEST_PAUSE_DOWNLOAD:
|
||||||
|
- mItf.requestPauseDownload();
|
||||||
|
- break;
|
||||||
|
- case MSG_SET_DOWNLOAD_FLAGS:
|
||||||
|
- mItf.setDownloadFlags(msg.getData().getInt(PARAMS_FLAGS));
|
||||||
|
- break;
|
||||||
|
- case MSG_REQUEST_DOWNLOAD_STATE:
|
||||||
|
- mItf.requestDownloadStatus();
|
||||||
|
- break;
|
||||||
|
- case MSG_REQUEST_CLIENT_UPDATE:
|
||||||
|
- mItf.onClientUpdated((Messenger) msg.getData().getParcelable(
|
||||||
|
- PARAM_MESSENGER));
|
||||||
|
- break;
|
||||||
|
+ Stub downloader = mDownloader.get();
|
||||||
|
+ if (downloader != null) {
|
||||||
|
+ downloader.handleMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- });
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void handleMessage(Message msg) {
|
||||||
|
+ switch (msg.what) {
|
||||||
|
+ case MSG_REQUEST_ABORT_DOWNLOAD:
|
||||||
|
+ mItf.requestAbortDownload();
|
||||||
|
+ break;
|
||||||
|
+ case MSG_REQUEST_CONTINUE_DOWNLOAD:
|
||||||
|
+ mItf.requestContinueDownload();
|
||||||
|
+ break;
|
||||||
|
+ case MSG_REQUEST_PAUSE_DOWNLOAD:
|
||||||
|
+ mItf.requestPauseDownload();
|
||||||
|
+ break;
|
||||||
|
+ case MSG_SET_DOWNLOAD_FLAGS:
|
||||||
|
+ mItf.setDownloadFlags(msg.getData().getInt(PARAMS_FLAGS));
|
||||||
|
+ break;
|
||||||
|
+ case MSG_REQUEST_DOWNLOAD_STATE:
|
||||||
|
+ mItf.requestDownloadStatus();
|
||||||
|
+ break;
|
||||||
|
+ case MSG_REQUEST_CLIENT_UPDATE:
|
||||||
|
+ mItf.onClientUpdated((Messenger)msg.getData().getParcelable(
|
||||||
|
+ PARAM_MESSENGER));
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // -- GODOT end --
|
||||||
|
|
||||||
|
public Stub(IDownloaderService itf) {
|
||||||
|
mItf = itf;
|
||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java
|
||||||
|
index e4b1b0f1c..36cd6aacf 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java
|
||||||
|
@@ -24,7 +24,10 @@ import android.os.StatFs;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
-import com.android.vending.expansion.downloader.R;
|
||||||
|
+// -- GODOT start --
|
||||||
|
+//import com.android.vending.expansion.downloader.R;
|
||||||
|
+import com.godot.game.R;
|
||||||
|
+// -- GODOT end --
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
@@ -146,12 +149,14 @@ public class Helpers {
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
- return String.format("%.2f",
|
||||||
|
+ // -- GODOT start --
|
||||||
|
+ return String.format(Locale.ENGLISH, "%.2f",
|
||||||
|
(float) overallProgress / (1024.0f * 1024.0f))
|
||||||
|
+ "MB /" +
|
||||||
|
- String.format("%.2f", (float) overallTotal /
|
||||||
|
+ String.format(Locale.ENGLISH, "%.2f", (float) overallTotal /
|
||||||
|
(1024.0f * 1024.0f))
|
||||||
|
+ "MB";
|
||||||
|
+ // -- GODOT end --
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -184,7 +189,9 @@ public class Helpers {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSpeedString(float bytesPerMillisecond) {
|
||||||
|
- return String.format("%.2f", bytesPerMillisecond * 1000 / 1024);
|
||||||
|
+ // -- GODOT start --
|
||||||
|
+ return String.format(Locale.ENGLISH, "%.2f", bytesPerMillisecond * 1000 / 1024);
|
||||||
|
+ // -- GODOT end --
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTimeRemaining(long durationInMilliseconds) {
|
||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/SystemFacade.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/SystemFacade.java
|
||||||
|
index 12edd97ab..a0e1165cc 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/expansion/downloader/SystemFacade.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/SystemFacade.java
|
||||||
|
@@ -26,6 +26,10 @@ import android.net.NetworkInfo;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
+// -- GODOT start --
|
||||||
|
+import android.annotation.SuppressLint;
|
||||||
|
+// -- GODOT end --
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Contains useful helper functions, typically tied to the application context.
|
||||||
|
*/
|
||||||
|
@@ -51,6 +55,7 @@ class SystemFacade {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @SuppressLint("MissingPermission")
|
||||||
|
NetworkInfo activeInfo = connectivity.getActiveNetworkInfo();
|
||||||
|
if (activeInfo == null) {
|
||||||
|
if (Constants.LOGVV) {
|
||||||
|
@@ -69,6 +74,7 @@ class SystemFacade {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @SuppressLint("MissingPermission")
|
||||||
|
NetworkInfo info = connectivity.getActiveNetworkInfo();
|
||||||
|
boolean isMobile = (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE);
|
||||||
|
TelephonyManager tm = (TelephonyManager) mContext
|
||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
|
||||||
|
index f1536e80e..4b214b22d 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
|
||||||
|
@@ -16,7 +16,11 @@
|
||||||
|
|
||||||
|
package com.google.android.vending.expansion.downloader.impl;
|
||||||
|
|
||||||
|
-import com.android.vending.expansion.downloader.R;
|
||||||
|
+// -- GODOT start --
|
||||||
|
+//import com.android.vending.expansion.downloader.R;
|
||||||
|
+import com.godot.game.R;
|
||||||
|
+// -- GODOT end --
|
||||||
|
+
|
||||||
|
import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
|
||||||
|
import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
|
||||||
|
import com.google.android.vending.expansion.downloader.Helpers;
|
||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
|
||||||
|
index b2e0e7af0..c114b8a64 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
|
||||||
|
@@ -146,8 +146,12 @@ public class DownloadThread {
|
||||||
|
|
||||||
|
try {
|
||||||
|
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||||
|
- wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Constants.TAG);
|
||||||
|
- wakeLock.acquire();
|
||||||
|
+ // -- GODOT start --
|
||||||
|
+ //wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Constants.TAG);
|
||||||
|
+ //wakeLock.acquire();
|
||||||
|
+ wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "org.godot.game:wakelock");
|
||||||
|
+ wakeLock.acquire(20 * 60 * 1000L /*20 minutes*/);
|
||||||
|
+ // -- GODOT end --
|
||||||
|
|
||||||
|
if (Constants.LOGV) {
|
||||||
|
Log.v(Constants.TAG, "initiating download for " + mInfo.mFileName);
|
||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
|
||||||
|
index 4babe476f..8d41a7690 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
|
||||||
|
@@ -50,6 +50,10 @@ import android.provider.Settings.Secure;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
+// -- GODOT start --
|
||||||
|
+import android.annotation.SuppressLint;
|
||||||
|
+// -- GODOT end --
|
||||||
|
+
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -578,6 +582,7 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
||||||
|
Log.w(Constants.TAG,
|
||||||
|
"couldn't get connectivity manager to poll network state");
|
||||||
|
} else {
|
||||||
|
+ @SuppressLint("MissingPermission")
|
||||||
|
NetworkInfo activeInfo = mConnectivityManager
|
||||||
|
.getActiveNetworkInfo();
|
||||||
|
updateNetworkState(activeInfo);
|
@ -0,0 +1,42 @@
|
|||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/licensing/PreferenceObfuscator.java b/platform/android/java/src/com/google/android/vending/licensing/PreferenceObfuscator.java
|
||||||
|
index 7c42bfc28..feb579af0 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/licensing/PreferenceObfuscator.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/licensing/PreferenceObfuscator.java
|
||||||
|
@@ -45,6 +45,9 @@ public class PreferenceObfuscator {
|
||||||
|
public void putString(String key, String value) {
|
||||||
|
if (mEditor == null) {
|
||||||
|
mEditor = mPreferences.edit();
|
||||||
|
+ // -- GODOT start --
|
||||||
|
+ mEditor.apply();
|
||||||
|
+ // -- GODOT end --
|
||||||
|
}
|
||||||
|
String obfuscatedValue = mObfuscator.obfuscate(value, key);
|
||||||
|
mEditor.putString(key, obfuscatedValue);
|
||||||
|
diff --git a/platform/android/java/src/com/google/android/vending/licensing/util/Base64.java b/platform/android/java/src/com/google/android/vending/licensing/util/Base64.java
|
||||||
|
index a0d2779af..a8bf65f9c 100644
|
||||||
|
--- a/platform/android/java/src/com/google/android/vending/licensing/util/Base64.java
|
||||||
|
+++ b/platform/android/java/src/com/google/android/vending/licensing/util/Base64.java
|
||||||
|
@@ -31,6 +31,10 @@ package com.google.android.vending.licensing.util;
|
||||||
|
* @version 1.3
|
||||||
|
*/
|
||||||
|
|
||||||
|
+// -- GODOT start --
|
||||||
|
+import com.godot.game.BuildConfig;
|
||||||
|
+// -- GODOT end --
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Base64 converter class. This code is not a full-blown MIME encoder;
|
||||||
|
* it simply converts binary data to base64 data and back.
|
||||||
|
@@ -341,7 +345,11 @@ public class Base64 {
|
||||||
|
e += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
- assert (e == outBuff.length);
|
||||||
|
+ // -- GODOT start --
|
||||||
|
+ //assert (e == outBuff.length);
|
||||||
|
+ if (BuildConfig.DEBUG && e != outBuff.length)
|
||||||
|
+ throw new RuntimeException();
|
||||||
|
+ // -- GODOT end --
|
||||||
|
return outBuff;
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ package com.google.android.vending.expansion.downloader;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the internal constants that are used in the download manager.
|
* Contains the internal constants that are used in the download manager.
|
||||||
* As a general rule, modifying these constants should be done with care.
|
* As a general rule, modifying these constants should be done with care.
|
||||||
@ -29,7 +30,8 @@ public class Constants {
|
|||||||
/**
|
/**
|
||||||
* Expansion path where we store obb files
|
* Expansion path where we store obb files
|
||||||
*/
|
*/
|
||||||
public static final String EXP_PATH = File.separator + "Android" + File.separator + "obb" + File.separator;
|
public static final String EXP_PATH = File.separator + "Android"
|
||||||
|
+ File.separator + "obb" + File.separator;
|
||||||
|
|
||||||
/** The intent that gets sent when the service must wake up for a retry */
|
/** The intent that gets sent when the service must wake up for a retry */
|
||||||
public static final String ACTION_RETRY = "android.intent.action.DOWNLOAD_WAKEUP";
|
public static final String ACTION_RETRY = "android.intent.action.DOWNLOAD_WAKEUP";
|
||||||
@ -230,4 +232,5 @@ public class Constants {
|
|||||||
* The wake duration to check to see if the process was killed.
|
* The wake duration to check to see if the process was killed.
|
||||||
*/
|
*/
|
||||||
public static final long ACTIVE_THREAD_WATCHDOG = 5*1000;
|
public static final long ACTIVE_THREAD_WATCHDOG = 5*1000;
|
||||||
|
|
||||||
}
|
}
|
@ -19,6 +19,7 @@ package com.google.android.vending.expansion.downloader;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains progress information about the active download(s).
|
* This class contains progress information about the active download(s).
|
||||||
*
|
*
|
||||||
@ -75,4 +76,5 @@ public class DownloadProgressInfo implements Parcelable {
|
|||||||
return new DownloadProgressInfo[i];
|
return new DownloadProgressInfo[i];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,10 @@ import android.os.Messenger;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class binds the service API to your application client. It contains the IDownloaderClient proxy,
|
* This class binds the service API to your application client. It contains the IDownloaderClient proxy,
|
||||||
@ -118,6 +121,7 @@ public class DownloaderClientMarshaller {
|
|||||||
/**
|
/**
|
||||||
* Target we publish for clients to send messages to IncomingHandler.
|
* Target we publish for clients to send messages to IncomingHandler.
|
||||||
*/
|
*/
|
||||||
|
// -- GODOT start --
|
||||||
private final MessengerHandlerClient mMsgHandler = new MessengerHandlerClient(this);
|
private final MessengerHandlerClient mMsgHandler = new MessengerHandlerClient(this);
|
||||||
final Messenger mMessenger = new Messenger(mMsgHandler);
|
final Messenger mMessenger = new Messenger(mMsgHandler);
|
||||||
|
|
||||||
@ -156,6 +160,7 @@ public class DownloaderClientMarshaller {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
public Stub(IDownloaderClient itf, Class<?> downloaderService) {
|
public Stub(IDownloaderClient itf, Class<?> downloaderService) {
|
||||||
mItf = itf;
|
mItf = itf;
|
||||||
@ -196,6 +201,7 @@ public class DownloaderClientMarshaller {
|
|||||||
} else {
|
} else {
|
||||||
mBound = true;
|
mBound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -287,4 +293,5 @@ public class DownloaderClientMarshaller {
|
|||||||
return DownloaderService.startDownloadServiceIfRequired(context, notificationClient,
|
return DownloaderService.startDownloadServiceIfRequired(context, notificationClient,
|
||||||
serviceClass);
|
serviceClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,10 @@ import android.os.Message;
|
|||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used by the client activity to proxy requests to the Downloader
|
* This class is used by the client activity to proxy requests to the Downloader
|
||||||
@ -108,6 +111,7 @@ public class DownloaderServiceMarshaller {
|
|||||||
|
|
||||||
private static class Stub implements IStub {
|
private static class Stub implements IStub {
|
||||||
private IDownloaderService mItf = null;
|
private IDownloaderService mItf = null;
|
||||||
|
// -- GODOT start --
|
||||||
private final MessengerHandlerServer mMsgHandler = new MessengerHandlerServer(this);
|
private final MessengerHandlerServer mMsgHandler = new MessengerHandlerServer(this);
|
||||||
final Messenger mMessenger = new Messenger(mMsgHandler);
|
final Messenger mMessenger = new Messenger(mMsgHandler);
|
||||||
|
|
||||||
@ -149,6 +153,7 @@ public class DownloaderServiceMarshaller {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
public Stub(IDownloaderService itf) {
|
public Stub(IDownloaderService itf) {
|
||||||
mItf = itf;
|
mItf = itf;
|
||||||
@ -161,10 +166,12 @@ public class DownloaderServiceMarshaller {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect(Context c) {
|
public void connect(Context c) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disconnect(Context c) {
|
public void disconnect(Context c) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,4 +197,5 @@ public class DownloaderServiceMarshaller {
|
|||||||
public static IStub CreateStub(IDownloaderService itf) {
|
public static IStub CreateStub(IDownloaderService itf) {
|
||||||
return new Stub(itf);
|
return new Stub(itf);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,10 @@ import android.os.StatFs;
|
|||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
|
//import com.android.vending.expansion.downloader.R;
|
||||||
import com.godot.game.R;
|
import com.godot.game.R;
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@ -113,7 +116,8 @@ public class Helpers {
|
|||||||
public static boolean isFilenameValid(String filename) {
|
public static boolean isFilenameValid(String filename) {
|
||||||
filename = filename.replaceFirst("/+", "/"); // normalize leading
|
filename = filename.replaceFirst("/+", "/"); // normalize leading
|
||||||
// slashes
|
// slashes
|
||||||
return filename.startsWith(Environment.getDownloadCacheDirectory().toString()) || filename.startsWith(Environment.getExternalStorageDirectory().toString());
|
return filename.startsWith(Environment.getDownloadCacheDirectory().toString())
|
||||||
|
|| filename.startsWith(Environment.getExternalStorageDirectory().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,10 +149,14 @@ public class Helpers {
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
// -- GODOT start --
|
||||||
return String.format(Locale.ENGLISH, "%.2f",
|
return String.format(Locale.ENGLISH, "%.2f",
|
||||||
(float)overallProgress / (1024.0f * 1024.0f)) +
|
(float) overallProgress / (1024.0f * 1024.0f))
|
||||||
"MB /" +
|
+ "MB /" +
|
||||||
String.format(Locale.ENGLISH, "%.2f", (float)overallTotal / (1024.0f * 1024.0f)) + "MB";
|
String.format(Locale.ENGLISH, "%.2f", (float) overallTotal /
|
||||||
|
(1024.0f * 1024.0f))
|
||||||
|
+ "MB";
|
||||||
|
// -- GODOT end --
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,7 +189,9 @@ public class Helpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getSpeedString(float bytesPerMillisecond) {
|
public static String getSpeedString(float bytesPerMillisecond) {
|
||||||
|
// -- GODOT start --
|
||||||
return String.format(Locale.ENGLISH, "%.2f", bytesPerMillisecond * 1000 / 1024);
|
return String.format(Locale.ENGLISH, "%.2f", bytesPerMillisecond * 1000 / 1024);
|
||||||
|
// -- GODOT end --
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getTimeRemaining(long durationInMilliseconds) {
|
public static String getTimeRemaining(long durationInMilliseconds) {
|
||||||
@ -210,7 +220,8 @@ public class Helpers {
|
|||||||
* Returns the filename (where the file should be saved) from info about a download
|
* Returns the filename (where the file should be saved) from info about a download
|
||||||
*/
|
*/
|
||||||
static public String generateSaveFileName(Context c, String fileName) {
|
static public String generateSaveFileName(Context c, String fileName) {
|
||||||
String path = getSaveFilePath(c) + File.separator + fileName;
|
String path = getSaveFilePath(c)
|
||||||
|
+ File.separator + fileName;
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,4 +363,5 @@ public class Helpers {
|
|||||||
return R.string.state_unknown;
|
return R.string.state_unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.google.android.vending.expansion.downloader;
|
package com.google.android.vending.expansion.downloader;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -27,6 +26,10 @@ import android.net.NetworkInfo;
|
|||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains useful helper functions, typically tied to the application context.
|
* Contains useful helper functions, typically tied to the application context.
|
||||||
*/
|
*/
|
||||||
|
3
platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
Executable file → Normal file
3
platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
Executable file → Normal file
@ -51,7 +51,8 @@ public abstract class CustomIntentService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
HandlerThread localHandlerThread = new HandlerThread("IntentService[" + this.mName + "]");
|
HandlerThread localHandlerThread = new HandlerThread("IntentService["
|
||||||
|
+ this.mName + "]");
|
||||||
localHandlerThread.start();
|
localHandlerThread.start();
|
||||||
this.mServiceLooper = localHandlerThread.getLooper();
|
this.mServiceLooper = localHandlerThread.getLooper();
|
||||||
this.mServiceHandler = new ServiceHandler(this.mServiceLooper);
|
this.mServiceHandler = new ServiceHandler(this.mServiceLooper);
|
||||||
|
@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
package com.google.android.vending.expansion.downloader.impl;
|
package com.google.android.vending.expansion.downloader.impl;
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
|
//import com.android.vending.expansion.downloader.R;
|
||||||
import com.godot.game.R;
|
import com.godot.game.R;
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
|
import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
|
||||||
import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
|
import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
|
||||||
import com.google.android.vending.expansion.downloader.Helpers;
|
import com.google.android.vending.expansion.downloader.Helpers;
|
||||||
@ -221,4 +225,5 @@ public class DownloadNotification implements IDownloaderClient {
|
|||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(Messenger m) {
|
public void onServiceConnected(Messenger m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,9 @@ public class DownloadThread {
|
|||||||
mService = service;
|
mService = service;
|
||||||
mNotification = notification;
|
mNotification = notification;
|
||||||
mDB = DownloadsDB.getDB(service);
|
mDB = DownloadsDB.getDB(service);
|
||||||
mUserAgent = "APKXDL (Linux; U; Android " + android.os.Build.VERSION.RELEASE + ";" + Locale.getDefault().toString() + "; " + android.os.Build.DEVICE + "/" + android.os.Build.ID + ")" +
|
mUserAgent = "APKXDL (Linux; U; Android " + android.os.Build.VERSION.RELEASE + ";"
|
||||||
|
+ Locale.getDefault().toString() + "; " + android.os.Build.DEVICE + "/"
|
||||||
|
+ android.os.Build.ID + ")" +
|
||||||
service.getPackageName();
|
service.getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,8 +146,12 @@ public class DownloadThread {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||||
|
// -- GODOT start --
|
||||||
|
//wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Constants.TAG);
|
||||||
|
//wakeLock.acquire();
|
||||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "org.godot.game:wakelock");
|
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "org.godot.game:wakelock");
|
||||||
wakeLock.acquire(20 * 60 * 1000L /*20 minutes*/);
|
wakeLock.acquire(20 * 60 * 1000L /*20 minutes*/);
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
if (Constants.LOGV) {
|
if (Constants.LOGV) {
|
||||||
Log.v(Constants.TAG, "initiating download for " + mInfo.mFileName);
|
Log.v(Constants.TAG, "initiating download for " + mInfo.mFileName);
|
||||||
@ -386,7 +392,10 @@ public class DownloadThread {
|
|||||||
*/
|
*/
|
||||||
private void reportProgress(State state, InnerState innerState) {
|
private void reportProgress(State state, InnerState innerState) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
if (innerState.mBytesSoFar - innerState.mBytesNotified > Constants.MIN_PROGRESS_STEP && now - innerState.mTimeLastNotification > Constants.MIN_PROGRESS_TIME) {
|
if (innerState.mBytesSoFar - innerState.mBytesNotified
|
||||||
|
> Constants.MIN_PROGRESS_STEP
|
||||||
|
&& now - innerState.mTimeLastNotification
|
||||||
|
> Constants.MIN_PROGRESS_TIME) {
|
||||||
// we store progress updates to the database here
|
// we store progress updates to the database here
|
||||||
mInfo.mCurrentBytes = innerState.mBytesSoFar;
|
mInfo.mCurrentBytes = innerState.mBytesSoFar;
|
||||||
mDB.updateDownloadCurrentBytes(mInfo);
|
mDB.updateDownloadCurrentBytes(mInfo);
|
||||||
@ -397,8 +406,10 @@ public class DownloadThread {
|
|||||||
long totalBytesSoFar = innerState.mBytesThisSession + mService.mBytesSoFar;
|
long totalBytesSoFar = innerState.mBytesThisSession + mService.mBytesSoFar;
|
||||||
|
|
||||||
if (Constants.LOGVV) {
|
if (Constants.LOGVV) {
|
||||||
Log.v(Constants.TAG, "downloaded " + mInfo.mCurrentBytes + " out of " + mInfo.mTotalBytes);
|
Log.v(Constants.TAG, "downloaded " + mInfo.mCurrentBytes + " out of "
|
||||||
Log.v(Constants.TAG, " total " + totalBytesSoFar + " out of " + mService.mTotalLength);
|
+ mInfo.mTotalBytes);
|
||||||
|
Log.v(Constants.TAG, " total " + totalBytesSoFar + " out of "
|
||||||
|
+ mService.mTotalLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
mService.notifyUpdateBytes(totalBytesSoFar);
|
mService.notifyUpdateBytes(totalBytesSoFar);
|
||||||
@ -452,7 +463,8 @@ public class DownloadThread {
|
|||||||
// }
|
// }
|
||||||
mDB.updateDownload(mInfo);
|
mDB.updateDownload(mInfo);
|
||||||
|
|
||||||
boolean lengthMismatched = (innerState.mHeaderContentLength != null) && (innerState.mBytesSoFar != Integer.parseInt(innerState.mHeaderContentLength));
|
boolean lengthMismatched = (innerState.mHeaderContentLength != null)
|
||||||
|
&& (innerState.mBytesSoFar != Integer.parseInt(innerState.mHeaderContentLength));
|
||||||
if (lengthMismatched) {
|
if (lengthMismatched) {
|
||||||
if (cannotResume(innerState)) {
|
if (cannotResume(innerState)) {
|
||||||
throw new StopRequest(DownloaderService.STATUS_CANNOT_RESUME,
|
throw new StopRequest(DownloaderService.STATUS_CANNOT_RESUME,
|
||||||
@ -485,7 +497,8 @@ public class DownloadThread {
|
|||||||
mInfo.mCurrentBytes = innerState.mBytesSoFar;
|
mInfo.mCurrentBytes = innerState.mBytesSoFar;
|
||||||
mDB.updateDownload(mInfo);
|
mDB.updateDownload(mInfo);
|
||||||
if (cannotResume(innerState)) {
|
if (cannotResume(innerState)) {
|
||||||
String message = "while reading response: " + ex.toString() + ", can't resume interrupted download with no ETag";
|
String message = "while reading response: " + ex.toString()
|
||||||
|
+ ", can't resume interrupted download with no ETag";
|
||||||
throw new StopRequest(DownloaderService.STATUS_CANNOT_RESUME,
|
throw new StopRequest(DownloaderService.STATUS_CANNOT_RESUME,
|
||||||
message, ex);
|
message, ex);
|
||||||
} else {
|
} else {
|
||||||
@ -514,7 +527,9 @@ public class DownloadThread {
|
|||||||
private void logNetworkState() {
|
private void logNetworkState() {
|
||||||
if (Constants.LOGX) {
|
if (Constants.LOGX) {
|
||||||
Log.i(Constants.TAG,
|
Log.i(Constants.TAG,
|
||||||
"Net " + (mService.getNetworkAvailabilityState(mDB) == DownloaderService.NETWORK_OK ? "Up" : "Down"));
|
"Net "
|
||||||
|
+ (mService.getNetworkAvailabilityState(mDB) == DownloaderService.NETWORK_OK ? "Up"
|
||||||
|
: "Down"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +646,9 @@ public class DownloadThread {
|
|||||||
Log.v(Constants.TAG, "Transfer-Encoding: " + headerTransferEncoding);
|
Log.v(Constants.TAG, "Transfer-Encoding: " + headerTransferEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean noSizeInfo = innerState.mHeaderContentLength == null && (headerTransferEncoding == null || !headerTransferEncoding.equalsIgnoreCase("chunked"));
|
boolean noSizeInfo = innerState.mHeaderContentLength == null
|
||||||
|
&& (headerTransferEncoding == null
|
||||||
|
|| !headerTransferEncoding.equalsIgnoreCase("chunked"));
|
||||||
if (noSizeInfo) {
|
if (noSizeInfo) {
|
||||||
throw new StopRequest(DownloaderService.STATUS_HTTP_DATA_ERROR,
|
throw new StopRequest(DownloaderService.STATUS_HTTP_DATA_ERROR,
|
||||||
"can't know size of download, giving up");
|
"can't know size of download, giving up");
|
||||||
@ -647,7 +664,8 @@ public class DownloadThread {
|
|||||||
if (responseCode == 503 && mInfo.mNumFailed < Constants.MAX_RETRIES) {
|
if (responseCode == 503 && mInfo.mNumFailed < Constants.MAX_RETRIES) {
|
||||||
handleServiceUnavailable(state, connection);
|
handleServiceUnavailable(state, connection);
|
||||||
}
|
}
|
||||||
int expectedStatus = innerState.mContinuingDownload ? 206 : DownloaderService.STATUS_SUCCESS;
|
int expectedStatus = innerState.mContinuingDownload ? 206
|
||||||
|
: DownloaderService.STATUS_SUCCESS;
|
||||||
if (responseCode != expectedStatus) {
|
if (responseCode != expectedStatus) {
|
||||||
handleOtherStatus(state, innerState, responseCode);
|
handleOtherStatus(state, innerState, responseCode);
|
||||||
} else {
|
} else {
|
||||||
@ -830,4 +848,5 @@ public class DownloadThread {
|
|||||||
}
|
}
|
||||||
mDB.updateDownload(mInfo);
|
mDB.updateDownload(mInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ import com.google.android.vending.licensing.LicenseChecker;
|
|||||||
import com.google.android.vending.licensing.LicenseCheckerCallback;
|
import com.google.android.vending.licensing.LicenseCheckerCallback;
|
||||||
import com.google.android.vending.licensing.Policy;
|
import com.google.android.vending.licensing.Policy;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
@ -51,6 +50,10 @@ import android.provider.Settings.Secure;
|
|||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,7 +188,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
* error).
|
* error).
|
||||||
*/
|
*/
|
||||||
public static boolean isStatusCompleted(int status) {
|
public static boolean isStatusCompleted(int status) {
|
||||||
return (status >= 200 && status < 300) || (status >= 400 && status < 600);
|
return (status >= 200 && status < 300)
|
||||||
|
|| (status >= 400 && status < 600);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -528,7 +532,10 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
mIsConnected = false;
|
mIsConnected = false;
|
||||||
updateNetworkType(-1, -1);
|
updateNetworkType(-1, -1);
|
||||||
}
|
}
|
||||||
mStateChanged = (mStateChanged || isConnected != mIsConnected || isFailover != mIsFailover || isCellularConnection != mIsCellularConnection || isRoaming != mIsRoaming || isAtLeast3G != mIsAtLeast3G);
|
mStateChanged = (mStateChanged || isConnected != mIsConnected
|
||||||
|
|| isFailover != mIsFailover
|
||||||
|
|| isCellularConnection != mIsCellularConnection
|
||||||
|
|| isRoaming != mIsRoaming || isAtLeast3G != mIsAtLeast3G);
|
||||||
if (Constants.LOGVV) {
|
if (Constants.LOGVV) {
|
||||||
if (mStateChanged) {
|
if (mStateChanged) {
|
||||||
Log.v(LOG_TAG, "Network state changed: ");
|
Log.v(LOG_TAG, "Network state changed: ");
|
||||||
@ -556,6 +563,7 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -628,7 +636,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
|
|
||||||
public static int startDownloadServiceIfRequired(Context context,
|
public static int startDownloadServiceIfRequired(Context context,
|
||||||
PendingIntent pendingIntent, Class<?> serviceClass)
|
PendingIntent pendingIntent, Class<?> serviceClass)
|
||||||
throws NameNotFoundException {
|
throws NameNotFoundException
|
||||||
|
{
|
||||||
String packageName = context.getPackageName();
|
String packageName = context.getPackageName();
|
||||||
String className = serviceClass.getName();
|
String className = serviceClass.getName();
|
||||||
|
|
||||||
@ -746,7 +755,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
public void run() {
|
public void run() {
|
||||||
setServiceRunning(true);
|
setServiceRunning(true);
|
||||||
mNotification.onDownloadStateChanged(IDownloaderClient.STATE_FETCHING_URL);
|
mNotification.onDownloadStateChanged(IDownloaderClient.STATE_FETCHING_URL);
|
||||||
String deviceId = Secure.ANDROID_ID;
|
String deviceId = Secure.getString(mContext.getContentResolver(),
|
||||||
|
Secure.ANDROID_ID);
|
||||||
|
|
||||||
final APKExpansionPolicy aep = new APKExpansionPolicy(mContext,
|
final APKExpansionPolicy aep = new APKExpansionPolicy(mContext,
|
||||||
new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId));
|
new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId));
|
||||||
@ -761,6 +771,7 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
getPublicKey() // Your public licensing key.
|
getPublicKey() // Your public licensing key.
|
||||||
);
|
);
|
||||||
checker.checkAccess(new LicenseCheckerCallback() {
|
checker.checkAccess(new LicenseCheckerCallback() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void allow(int reason) {
|
public void allow(int reason) {
|
||||||
try {
|
try {
|
||||||
@ -798,7 +809,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
// was delivered by Market or
|
// was delivered by Market or
|
||||||
// through
|
// through
|
||||||
// another mechanism
|
// another mechanism
|
||||||
Log.d(LOG_TAG, "file " + di.mFileName + " found. Not downloading.");
|
Log.d(LOG_TAG, "file " + di.mFileName
|
||||||
|
+ " found. Not downloading.");
|
||||||
di.mStatus = STATUS_SUCCESS;
|
di.mStatus = STATUS_SUCCESS;
|
||||||
di.mTotalBytes = fileSize;
|
di.mTotalBytes = fileSize;
|
||||||
di.mCurrentBytes = fileSize;
|
di.mCurrentBytes = fileSize;
|
||||||
@ -854,7 +866,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dontAllow(int reason) {
|
public void dontAllow(int reason) {
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case Policy.NOT_LICENSED:
|
case Policy.NOT_LICENSED:
|
||||||
mNotification
|
mNotification
|
||||||
@ -868,6 +881,7 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
} finally {
|
} finally {
|
||||||
setServiceRunning(false);
|
setServiceRunning(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -879,8 +893,11 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
setServiceRunning(false);
|
setServiceRunning(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -947,7 +964,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
PendingIntent.FLAG_ONE_SHOT);
|
PendingIntent.FLAG_ONE_SHOT);
|
||||||
alarms.set(
|
alarms.set(
|
||||||
AlarmManager.RTC_WAKEUP,
|
AlarmManager.RTC_WAKEUP,
|
||||||
System.currentTimeMillis() + wakeUp, mAlarmIntent);
|
System.currentTimeMillis() + wakeUp, mAlarmIntent
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAlarms() {
|
private void cancelAlarms() {
|
||||||
@ -976,7 +994,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
pollNetworkState();
|
pollNetworkState();
|
||||||
if (mStateChanged && !isServiceRunning()) {
|
if (mStateChanged
|
||||||
|
&& !isServiceRunning()) {
|
||||||
Log.d(Constants.TAG, "InnerBroadcastReceiver Called");
|
Log.d(Constants.TAG, "InnerBroadcastReceiver Called");
|
||||||
Intent fileIntent = new Intent(context, mService.getClass());
|
Intent fileIntent = new Intent(context, mService.getClass());
|
||||||
fileIntent.putExtra(EXTRA_PENDING_INTENT, mPendingIntent);
|
fileIntent.putExtra(EXTRA_PENDING_INTENT, mPendingIntent);
|
||||||
@ -1000,7 +1019,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
final PendingIntent pendingIntent = (PendingIntent) intent
|
final PendingIntent pendingIntent = (PendingIntent) intent
|
||||||
.getParcelableExtra(EXTRA_PENDING_INTENT);
|
.getParcelableExtra(EXTRA_PENDING_INTENT);
|
||||||
|
|
||||||
if (null != pendingIntent) {
|
if (null != pendingIntent)
|
||||||
|
{
|
||||||
mNotification.setClientIntent(pendingIntent);
|
mNotification.setClientIntent(pendingIntent);
|
||||||
mPendingIntent = pendingIntent;
|
mPendingIntent = pendingIntent;
|
||||||
} else if (null != mPendingIntent) {
|
} else if (null != mPendingIntent) {
|
||||||
@ -1201,7 +1221,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
* download
|
* download
|
||||||
*/
|
*/
|
||||||
public String generateTempSaveFileName(String fileName) {
|
public String generateTempSaveFileName(String fileName) {
|
||||||
String path = Helpers.getSaveFilePath(this) + File.separator + fileName + TEMP_EXT;
|
String path = Helpers.getSaveFilePath(this)
|
||||||
|
+ File.separator + fileName + TEMP_EXT;
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1217,6 +1238,7 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
Log.d(Constants.TAG, "External media not mounted: " + path);
|
Log.d(Constants.TAG, "External media not mounted: " + path);
|
||||||
throw new GenerateSaveFileError(STATUS_DEVICE_NOT_FOUND_ERROR,
|
throw new GenerateSaveFileError(STATUS_DEVICE_NOT_FOUND_ERROR,
|
||||||
"external media is not yet mounted");
|
"external media is not yet mounted");
|
||||||
|
|
||||||
}
|
}
|
||||||
if (expPath.exists()) {
|
if (expPath.exists()) {
|
||||||
Log.d(Constants.TAG, "File already exists: " + path);
|
Log.d(Constants.TAG, "File already exists: " + path);
|
||||||
@ -1279,7 +1301,8 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
long bytesInSample = totalBytesSoFar - mBytesAtSample;
|
long bytesInSample = totalBytesSoFar - mBytesAtSample;
|
||||||
float currentSpeedSample = (float) bytesInSample / (float) timePassed;
|
float currentSpeedSample = (float) bytesInSample / (float) timePassed;
|
||||||
if (0 != mAverageDownloadSpeed) {
|
if (0 != mAverageDownloadSpeed) {
|
||||||
mAverageDownloadSpeed = SMOOTHING_FACTOR * currentSpeedSample + (1 - SMOOTHING_FACTOR) * mAverageDownloadSpeed;
|
mAverageDownloadSpeed = SMOOTHING_FACTOR * currentSpeedSample
|
||||||
|
+ (1 - SMOOTHING_FACTOR) * mAverageDownloadSpeed;
|
||||||
} else {
|
} else {
|
||||||
mAverageDownloadSpeed = currentSpeedSample;
|
mAverageDownloadSpeed = currentSpeedSample;
|
||||||
}
|
}
|
||||||
@ -1293,7 +1316,9 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
new DownloadProgressInfo(mTotalLength,
|
new DownloadProgressInfo(mTotalLength,
|
||||||
totalBytesSoFar,
|
totalBytesSoFar,
|
||||||
timeRemaining,
|
timeRemaining,
|
||||||
mAverageDownloadSpeed));
|
mAverageDownloadSpeed)
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1317,4 +1342,5 @@ public abstract class DownloaderService extends CustomIntentService implements I
|
|||||||
this.mClientMessenger = clientMessenger;
|
this.mClientMessenger = clientMessenger;
|
||||||
mNotification.setMessenger(mClientMessenger);
|
mNotification.setMessenger(mClientMessenger);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
85
platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
Executable file → Normal file
85
platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
Executable file → Normal file
@ -49,7 +49,9 @@ public class DownloadsDB {
|
|||||||
private SQLiteStatement getDownloadByIndexStatement() {
|
private SQLiteStatement getDownloadByIndexStatement() {
|
||||||
if (null == mGetDownloadByIndex) {
|
if (null == mGetDownloadByIndex) {
|
||||||
mGetDownloadByIndex = mHelper.getReadableDatabase().compileStatement(
|
mGetDownloadByIndex = mHelper.getReadableDatabase().compileStatement(
|
||||||
"SELECT " + BaseColumns._ID + " FROM " + DownloadColumns.TABLE_NAME + " WHERE " + DownloadColumns.INDEX + " = ?");
|
"SELECT " + BaseColumns._ID + " FROM "
|
||||||
|
+ DownloadColumns.TABLE_NAME + " WHERE "
|
||||||
|
+ DownloadColumns.INDEX + " = ?");
|
||||||
}
|
}
|
||||||
return mGetDownloadByIndex;
|
return mGetDownloadByIndex;
|
||||||
}
|
}
|
||||||
@ -57,8 +59,8 @@ public class DownloadsDB {
|
|||||||
private SQLiteStatement getUpdateCurrentBytesStatement() {
|
private SQLiteStatement getUpdateCurrentBytesStatement() {
|
||||||
if (null == mUpdateCurrentBytes) {
|
if (null == mUpdateCurrentBytes) {
|
||||||
mUpdateCurrentBytes = mHelper.getReadableDatabase().compileStatement(
|
mUpdateCurrentBytes = mHelper.getReadableDatabase().compileStatement(
|
||||||
"UPDATE " + DownloadColumns.TABLE_NAME + " SET " + DownloadColumns.CURRENTBYTES + " = ?"
|
"UPDATE " + DownloadColumns.TABLE_NAME + " SET " + DownloadColumns.CURRENTBYTES
|
||||||
+
|
+ " = ?" +
|
||||||
" WHERE " + DownloadColumns.INDEX + " = ?");
|
" WHERE " + DownloadColumns.INDEX + " = ?");
|
||||||
}
|
}
|
||||||
return mUpdateCurrentBytes;
|
return mUpdateCurrentBytes;
|
||||||
@ -74,8 +76,8 @@ public class DownloadsDB {
|
|||||||
BaseColumns._ID + "," +
|
BaseColumns._ID + "," +
|
||||||
MetadataColumns.DOWNLOAD_STATUS + "," +
|
MetadataColumns.DOWNLOAD_STATUS + "," +
|
||||||
MetadataColumns.FLAGS +
|
MetadataColumns.FLAGS +
|
||||||
" FROM " + MetadataColumns.TABLE_NAME + " LIMIT 1",
|
" FROM "
|
||||||
null);
|
+ MetadataColumns.TABLE_NAME + " LIMIT 1", null);
|
||||||
if (null != cur && cur.moveToFirst()) {
|
if (null != cur && cur.moveToFirst()) {
|
||||||
mVersionCode = cur.getInt(0);
|
mVersionCode = cur.getInt(0);
|
||||||
mMetadataRowID = cur.getLong(1);
|
mMetadataRowID = cur.getLong(1);
|
||||||
@ -93,8 +95,8 @@ public class DownloadsDB {
|
|||||||
itemcur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
|
itemcur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
|
||||||
DownloadColumns.FILENAME + " = ?",
|
DownloadColumns.FILENAME + " = ?",
|
||||||
new String[] {
|
new String[] {
|
||||||
fileName },
|
fileName
|
||||||
null, null, null);
|
}, null, null, null);
|
||||||
if (null != itemcur && itemcur.moveToFirst()) {
|
if (null != itemcur && itemcur.moveToFirst()) {
|
||||||
return getDownloadInfoFromCursor(itemcur);
|
return getDownloadInfoFromCursor(itemcur);
|
||||||
}
|
}
|
||||||
@ -208,7 +210,8 @@ public class DownloadsDB {
|
|||||||
public void onUpgrade(SQLiteDatabase paramSQLiteDatabase,
|
public void onUpgrade(SQLiteDatabase paramSQLiteDatabase,
|
||||||
int paramInt1, int paramInt2) {
|
int paramInt1, int paramInt2) {
|
||||||
Log.w(DownloadsContentDBHelper.class.getName(),
|
Log.w(DownloadsContentDBHelper.class.getName(),
|
||||||
"Upgrading database from version " + paramInt1 + " to " + paramInt2 + ", which will destroy all old data");
|
"Upgrading database from version " + paramInt1 + " to "
|
||||||
|
+ paramInt2 + ", which will destroy all old data");
|
||||||
dropTables(paramSQLiteDatabase);
|
dropTables(paramSQLiteDatabase);
|
||||||
onCreate(paramSQLiteDatabase);
|
onCreate(paramSQLiteDatabase);
|
||||||
}
|
}
|
||||||
@ -220,9 +223,17 @@ public class DownloadsDB {
|
|||||||
public static final String FLAGS = "DOWNLOADFLAGS";
|
public static final String FLAGS = "DOWNLOADFLAGS";
|
||||||
|
|
||||||
public static final String[][] SCHEMA = {
|
public static final String[][] SCHEMA = {
|
||||||
{ BaseColumns._ID, "INTEGER PRIMARY KEY" },
|
{
|
||||||
{ APKVERSION, "INTEGER" }, { DOWNLOAD_STATUS, "INTEGER" },
|
BaseColumns._ID, "INTEGER PRIMARY KEY"
|
||||||
{ FLAGS, "INTEGER" }
|
},
|
||||||
|
{
|
||||||
|
APKVERSION, "INTEGER"
|
||||||
|
}, {
|
||||||
|
DOWNLOAD_STATUS, "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
FLAGS, "INTEGER"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
public static final String TABLE_NAME = "MetadataColumns";
|
public static final String TABLE_NAME = "MetadataColumns";
|
||||||
public static final String _ID = "MetadataColumns._id";
|
public static final String _ID = "MetadataColumns._id";
|
||||||
@ -245,13 +256,39 @@ public class DownloadsDB {
|
|||||||
public static final String REDIRECT_COUNT = "REDIRECTCOUNT";
|
public static final String REDIRECT_COUNT = "REDIRECTCOUNT";
|
||||||
|
|
||||||
public static final String[][] SCHEMA = {
|
public static final String[][] SCHEMA = {
|
||||||
{ BaseColumns._ID, "INTEGER PRIMARY KEY" },
|
{
|
||||||
{ INDEX, "INTEGER UNIQUE" }, { URI, "TEXT" },
|
BaseColumns._ID, "INTEGER PRIMARY KEY"
|
||||||
{ FILENAME, "TEXT UNIQUE" }, { ETAG, "TEXT" },
|
},
|
||||||
{ TOTALBYTES, "INTEGER" }, { CURRENTBYTES, "INTEGER" },
|
{
|
||||||
{ LASTMOD, "INTEGER" }, { STATUS, "INTEGER" },
|
INDEX, "INTEGER UNIQUE"
|
||||||
{ CONTROL, "INTEGER" }, { NUM_FAILED, "INTEGER" },
|
}, {
|
||||||
{ RETRY_AFTER, "INTEGER" }, { REDIRECT_COUNT, "INTEGER" }
|
URI, "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
FILENAME, "TEXT UNIQUE"
|
||||||
|
}, {
|
||||||
|
ETAG, "TEXT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TOTALBYTES, "INTEGER"
|
||||||
|
}, {
|
||||||
|
CURRENTBYTES, "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
LASTMOD, "INTEGER"
|
||||||
|
}, {
|
||||||
|
STATUS, "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
CONTROL, "INTEGER"
|
||||||
|
}, {
|
||||||
|
NUM_FAILED, "INTEGER"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RETRY_AFTER, "INTEGER"
|
||||||
|
}, {
|
||||||
|
REDIRECT_COUNT, "INTEGER"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
public static final String TABLE_NAME = "DownloadColumns";
|
public static final String TABLE_NAME = "DownloadColumns";
|
||||||
public static final String _ID = "DownloadColumns._id";
|
public static final String _ID = "DownloadColumns._id";
|
||||||
@ -328,7 +365,9 @@ public class DownloadsDB {
|
|||||||
|
|
||||||
public boolean isDownloadRequired() {
|
public boolean isDownloadRequired() {
|
||||||
final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
|
final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
|
||||||
Cursor cur = sqldb.rawQuery("SELECT Count(*) FROM " + DownloadColumns.TABLE_NAME + " WHERE " + DownloadColumns.STATUS + " <> 0", null);
|
Cursor cur = sqldb.rawQuery("SELECT Count(*) FROM "
|
||||||
|
+ DownloadColumns.TABLE_NAME + " WHERE "
|
||||||
|
+ DownloadColumns.STATUS + " <> 0", null);
|
||||||
try {
|
try {
|
||||||
if (null != cur && cur.moveToFirst()) {
|
if (null != cur && cur.moveToFirst()) {
|
||||||
return 0 == cur.getInt(0);
|
return 0 == cur.getInt(0);
|
||||||
@ -410,8 +449,8 @@ public class DownloadsDB {
|
|||||||
cur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
|
cur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
|
||||||
DownloadColumns.FILENAME + "= ?",
|
DownloadColumns.FILENAME + "= ?",
|
||||||
new String[] {
|
new String[] {
|
||||||
di.mFileName },
|
di.mFileName
|
||||||
null, null, null);
|
}, null, null, null);
|
||||||
if (null != cur && cur.moveToFirst()) {
|
if (null != cur && cur.moveToFirst()) {
|
||||||
setDownloadInfoFromCursor(di, cur);
|
setDownloadInfoFromCursor(di, cur);
|
||||||
return true;
|
return true;
|
||||||
@ -439,7 +478,8 @@ public class DownloadsDB {
|
|||||||
|
|
||||||
public DownloadInfo getDownloadInfoFromCursor(Cursor cur) {
|
public DownloadInfo getDownloadInfoFromCursor(Cursor cur) {
|
||||||
DownloadInfo di = new DownloadInfo(cur.getInt(INDEX_IDX),
|
DownloadInfo di = new DownloadInfo(cur.getInt(INDEX_IDX),
|
||||||
cur.getString(FILENAME_IDX), this.getClass().getPackage().getName());
|
cur.getString(FILENAME_IDX), this.getClass().getPackage()
|
||||||
|
.getName());
|
||||||
setDownloadInfoFromCursor(di, cur);
|
setDownloadInfoFromCursor(di, cur);
|
||||||
return di;
|
return di;
|
||||||
}
|
}
|
||||||
@ -466,4 +506,5 @@ public class DownloadsDB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,8 @@ public final class HttpDateTime {
|
|||||||
|
|
||||||
private static int getDate(String dateString) {
|
private static int getDate(String dateString) {
|
||||||
if (dateString.length() == 2) {
|
if (dateString.length() == 2) {
|
||||||
return (dateString.charAt(0) - '0') * 10 + (dateString.charAt(1) - '0');
|
return (dateString.charAt(0) - '0') * 10
|
||||||
|
+ (dateString.charAt(1) - '0');
|
||||||
} else {
|
} else {
|
||||||
return (dateString.charAt(0) - '0');
|
return (dateString.charAt(0) - '0');
|
||||||
}
|
}
|
||||||
@ -154,7 +155,8 @@ public final class HttpDateTime {
|
|||||||
|
|
||||||
private static int getYear(String yearString) {
|
private static int getYear(String yearString) {
|
||||||
if (yearString.length() == 2) {
|
if (yearString.length() == 2) {
|
||||||
int year = (yearString.charAt(0) - '0') * 10 + (yearString.charAt(1) - '0');
|
int year = (yearString.charAt(0) - '0') * 10
|
||||||
|
+ (yearString.charAt(1) - '0');
|
||||||
if (year >= 70) {
|
if (year >= 70) {
|
||||||
return year + 1900;
|
return year + 1900;
|
||||||
} else {
|
} else {
|
||||||
@ -162,10 +164,15 @@ public final class HttpDateTime {
|
|||||||
}
|
}
|
||||||
} else if (yearString.length() == 3) {
|
} else if (yearString.length() == 3) {
|
||||||
// According to RFC 2822, three digit years should be added to 1900.
|
// According to RFC 2822, three digit years should be added to 1900.
|
||||||
int year = (yearString.charAt(0) - '0') * 100 + (yearString.charAt(1) - '0') * 10 + (yearString.charAt(2) - '0');
|
int year = (yearString.charAt(0) - '0') * 100
|
||||||
|
+ (yearString.charAt(1) - '0') * 10
|
||||||
|
+ (yearString.charAt(2) - '0');
|
||||||
return year + 1900;
|
return year + 1900;
|
||||||
} else if (yearString.length() == 4) {
|
} else if (yearString.length() == 4) {
|
||||||
return (yearString.charAt(0) - '0') * 1000 + (yearString.charAt(1) - '0') * 100 + (yearString.charAt(2) - '0') * 10 + (yearString.charAt(3) - '0');
|
return (yearString.charAt(0) - '0') * 1000
|
||||||
|
+ (yearString.charAt(1) - '0') * 100
|
||||||
|
+ (yearString.charAt(2) - '0') * 10
|
||||||
|
+ (yearString.charAt(3) - '0');
|
||||||
} else {
|
} else {
|
||||||
return 1970;
|
return 1970;
|
||||||
}
|
}
|
||||||
@ -180,11 +187,13 @@ public final class HttpDateTime {
|
|||||||
// Skip ':'
|
// Skip ':'
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
int minute = (timeString.charAt(i++) - '0') * 10 + (timeString.charAt(i++) - '0');
|
int minute = (timeString.charAt(i++) - '0') * 10
|
||||||
|
+ (timeString.charAt(i++) - '0');
|
||||||
// Skip ':'
|
// Skip ':'
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
int second = (timeString.charAt(i++) - '0') * 10 + (timeString.charAt(i++) - '0');
|
int second = (timeString.charAt(i++) - '0') * 10
|
||||||
|
+ (timeString.charAt(i++) - '0');
|
||||||
|
|
||||||
return new TimeOfDay(hour, minute, second);
|
return new TimeOfDay(hour, minute, second);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,8 @@ public class AESObfuscator implements Obfuscator {
|
|||||||
private static final String UTF8 = "UTF-8";
|
private static final String UTF8 = "UTF-8";
|
||||||
private static final String KEYGEN_ALGORITHM = "PBEWITHSHAAND256BITAES-CBC-BC";
|
private static final String KEYGEN_ALGORITHM = "PBEWITHSHAAND256BITAES-CBC-BC";
|
||||||
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
|
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
|
||||||
private static final byte[] IV = { 16, 74, 71, -80, 32, 101, -47, 72, 117, -14, 0, -29, 70, 65, -12, 74 };
|
private static final byte[] IV =
|
||||||
|
{ 16, 74, 71, -80, 32, 101, -47, 72, 117, -14, 0, -29, 70, 65, -12, 74 };
|
||||||
private static final String header = "com.google.android.vending.licensing.AESObfuscator-1|";
|
private static final String header = "com.google.android.vending.licensing.AESObfuscator-1|";
|
||||||
|
|
||||||
private Cipher mEncryptor;
|
private Cipher mEncryptor;
|
||||||
@ -92,8 +93,7 @@ public class AESObfuscator implements Obfuscator {
|
|||||||
// where the block size is correct during decryption.
|
// where the block size is correct during decryption.
|
||||||
int headerIndex = result.indexOf(header+key);
|
int headerIndex = result.indexOf(header+key);
|
||||||
if (headerIndex != 0) {
|
if (headerIndex != 0) {
|
||||||
throw new ValidationException("Header not found (invalid data or key)"
|
throw new ValidationException("Header not found (invalid data or key)" + ":" +
|
||||||
+ ":" +
|
|
||||||
obfuscated);
|
obfuscated);
|
||||||
}
|
}
|
||||||
return result.substring(header.length()+key.length(), result.length());
|
return result.substring(header.length()+key.length(), result.length());
|
||||||
|
@ -410,4 +410,5 @@ public class APKExpansionPolicy implements Policy {
|
|||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is auto-generated. DO NOT MODIFY.
|
|
||||||
* Original file: aidl/ILicenseResultListener.aidl
|
|
||||||
*/
|
|
||||||
package com.google.android.vending.licensing;
|
|
||||||
import java.lang.String;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.IInterface;
|
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Parcel;
|
|
||||||
public interface ILicenseResultListener extends android.os.IInterface {
|
|
||||||
/** Local-side IPC implementation stub class. */
|
|
||||||
public static abstract class Stub extends android.os.Binder implements com.google.android.vending.licensing.ILicenseResultListener {
|
|
||||||
private static final java.lang.String DESCRIPTOR = "com.android.vending.licensing.ILicenseResultListener";
|
|
||||||
/** Construct the stub at attach it to the interface. */
|
|
||||||
public Stub() {
|
|
||||||
this.attachInterface(this, DESCRIPTOR);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Cast an IBinder object into an ILicenseResultListener interface,
|
|
||||||
* generating a proxy if needed.
|
|
||||||
*/
|
|
||||||
public static com.google.android.vending.licensing.ILicenseResultListener asInterface(android.os.IBinder obj) {
|
|
||||||
if ((obj == null)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
|
|
||||||
if (((iin != null) && (iin instanceof com.google.android.vending.licensing.ILicenseResultListener))) {
|
|
||||||
return ((com.google.android.vending.licensing.ILicenseResultListener)iin);
|
|
||||||
}
|
|
||||||
return new com.google.android.vending.licensing.ILicenseResultListener.Stub.Proxy(obj);
|
|
||||||
}
|
|
||||||
public android.os.IBinder asBinder() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
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_verifyLicense: {
|
|
||||||
data.enforceInterface(DESCRIPTOR);
|
|
||||||
int _arg0;
|
|
||||||
_arg0 = data.readInt();
|
|
||||||
java.lang.String _arg1;
|
|
||||||
_arg1 = data.readString();
|
|
||||||
java.lang.String _arg2;
|
|
||||||
_arg2 = data.readString();
|
|
||||||
this.verifyLicense(_arg0, _arg1, _arg2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onTransact(code, data, reply, flags);
|
|
||||||
}
|
|
||||||
private static class Proxy implements com.google.android.vending.licensing.ILicenseResultListener {
|
|
||||||
private android.os.IBinder mRemote;
|
|
||||||
Proxy(android.os.IBinder remote) {
|
|
||||||
mRemote = remote;
|
|
||||||
}
|
|
||||||
public android.os.IBinder asBinder() {
|
|
||||||
return mRemote;
|
|
||||||
}
|
|
||||||
public java.lang.String getInterfaceDescriptor() {
|
|
||||||
return DESCRIPTOR;
|
|
||||||
}
|
|
||||||
public void verifyLicense(int responseCode, java.lang.String signedData, java.lang.String signature) throws android.os.RemoteException {
|
|
||||||
android.os.Parcel _data = android.os.Parcel.obtain();
|
|
||||||
try {
|
|
||||||
_data.writeInterfaceToken(DESCRIPTOR);
|
|
||||||
_data.writeInt(responseCode);
|
|
||||||
_data.writeString(signedData);
|
|
||||||
_data.writeString(signature);
|
|
||||||
mRemote.transact(Stub.TRANSACTION_verifyLicense, _data, null, IBinder.FLAG_ONEWAY);
|
|
||||||
} finally {
|
|
||||||
_data.recycle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static final int TRANSACTION_verifyLicense = (IBinder.FIRST_CALL_TRANSACTION + 0);
|
|
||||||
}
|
|
||||||
public void verifyLicense(int responseCode, java.lang.String signedData, java.lang.String signature) throws android.os.RemoteException;
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is auto-generated. DO NOT MODIFY.
|
|
||||||
* Original file: aidl/ILicensingService.aidl
|
|
||||||
*/
|
|
||||||
package com.google.android.vending.licensing;
|
|
||||||
import java.lang.String;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.IInterface;
|
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Parcel;
|
|
||||||
public interface ILicensingService extends android.os.IInterface {
|
|
||||||
/** Local-side IPC implementation stub class. */
|
|
||||||
public static abstract class Stub extends android.os.Binder implements com.google.android.vending.licensing.ILicensingService {
|
|
||||||
private static final java.lang.String DESCRIPTOR = "com.android.vending.licensing.ILicensingService";
|
|
||||||
/** Construct the stub at attach it to the interface. */
|
|
||||||
public Stub() {
|
|
||||||
this.attachInterface(this, DESCRIPTOR);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Cast an IBinder object into an ILicensingService interface,
|
|
||||||
* generating a proxy if needed.
|
|
||||||
*/
|
|
||||||
public static com.google.android.vending.licensing.ILicensingService asInterface(android.os.IBinder obj) {
|
|
||||||
if ((obj == null)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
|
|
||||||
if (((iin != null) && (iin instanceof com.google.android.vending.licensing.ILicensingService))) {
|
|
||||||
return ((com.google.android.vending.licensing.ILicensingService)iin);
|
|
||||||
}
|
|
||||||
return new com.google.android.vending.licensing.ILicensingService.Stub.Proxy(obj);
|
|
||||||
}
|
|
||||||
public android.os.IBinder asBinder() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
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_checkLicense: {
|
|
||||||
data.enforceInterface(DESCRIPTOR);
|
|
||||||
long _arg0;
|
|
||||||
_arg0 = data.readLong();
|
|
||||||
java.lang.String _arg1;
|
|
||||||
_arg1 = data.readString();
|
|
||||||
com.google.android.vending.licensing.ILicenseResultListener _arg2;
|
|
||||||
_arg2 = com.google.android.vending.licensing.ILicenseResultListener.Stub.asInterface(data.readStrongBinder());
|
|
||||||
this.checkLicense(_arg0, _arg1, _arg2);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onTransact(code, data, reply, flags);
|
|
||||||
}
|
|
||||||
private static class Proxy implements com.google.android.vending.licensing.ILicensingService {
|
|
||||||
private android.os.IBinder mRemote;
|
|
||||||
Proxy(android.os.IBinder remote) {
|
|
||||||
mRemote = remote;
|
|
||||||
}
|
|
||||||
public android.os.IBinder asBinder() {
|
|
||||||
return mRemote;
|
|
||||||
}
|
|
||||||
public java.lang.String getInterfaceDescriptor() {
|
|
||||||
return DESCRIPTOR;
|
|
||||||
}
|
|
||||||
public void checkLicense(long nonce, java.lang.String packageName, com.google.android.vending.licensing.ILicenseResultListener listener) throws android.os.RemoteException {
|
|
||||||
android.os.Parcel _data = android.os.Parcel.obtain();
|
|
||||||
try {
|
|
||||||
_data.writeInterfaceToken(DESCRIPTOR);
|
|
||||||
_data.writeLong(nonce);
|
|
||||||
_data.writeString(packageName);
|
|
||||||
_data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
|
|
||||||
mRemote.transact(Stub.TRANSACTION_checkLicense, _data, null, IBinder.FLAG_ONEWAY);
|
|
||||||
} finally {
|
|
||||||
_data.recycle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static final int TRANSACTION_checkLicense = (IBinder.FIRST_CALL_TRANSACTION + 0);
|
|
||||||
}
|
|
||||||
public void checkLicense(long nonce, java.lang.String packageName, com.google.android.vending.licensing.ILicenseResultListener listener) throws android.os.RemoteException;
|
|
||||||
}
|
|
@ -29,8 +29,8 @@ import android.os.RemoteException;
|
|||||||
import android.provider.Settings.Secure;
|
import android.provider.Settings.Secure;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.android.vending.licensing.ILicenseResultListener;
|
import com.android.vending.licensing.ILicenseResultListener;
|
||||||
import com.google.android.vending.licensing.ILicensingService;
|
import com.android.vending.licensing.ILicensingService;
|
||||||
import com.google.android.vending.licensing.util.Base64;
|
import com.google.android.vending.licensing.util.Base64;
|
||||||
import com.google.android.vending.licensing.util.Base64DecoderException;
|
import com.google.android.vending.licensing.util.Base64DecoderException;
|
||||||
|
|
||||||
@ -287,13 +287,15 @@ public class LicenseChecker implements ServiceConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (logResponse) {
|
if (logResponse) {
|
||||||
String android_id = Secure.ANDROID_ID;
|
String android_id = Secure.getString(mContext.getContentResolver(),
|
||||||
|
Secure.ANDROID_ID);
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
Log.d(TAG, "Server Failure: " + stringError);
|
Log.d(TAG, "Server Failure: " + stringError);
|
||||||
Log.d(TAG, "Android ID: " + android_id);
|
Log.d(TAG, "Android ID: " + android_id);
|
||||||
Log.d(TAG, "Time: " + date.toGMTString());
|
Log.d(TAG, "Time: " + date.toGMTString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,7 @@ class LicenseValidator {
|
|||||||
// Verify signature.
|
// Verify signature.
|
||||||
try {
|
try {
|
||||||
if (TextUtils.isEmpty(signedData)) {
|
if (TextUtils.isEmpty(signedData)) {
|
||||||
Log.e(TAG, "Signature verification failed: signedData is empty. "
|
Log.e(TAG, "Signature verification failed: signedData is empty. " +
|
||||||
+
|
|
||||||
"(Device not signed-in to any Google accounts?)");
|
"(Device not signed-in to any Google accounts?)");
|
||||||
handleInvalidResponse();
|
handleInvalidResponse();
|
||||||
return;
|
return;
|
||||||
|
@ -45,7 +45,9 @@ public class PreferenceObfuscator {
|
|||||||
public void putString(String key, String value) {
|
public void putString(String key, String value) {
|
||||||
if (mEditor == null) {
|
if (mEditor == null) {
|
||||||
mEditor = mPreferences.edit();
|
mEditor = mPreferences.edit();
|
||||||
|
// -- GODOT start --
|
||||||
mEditor.apply();
|
mEditor.apply();
|
||||||
|
// -- GODOT end --
|
||||||
}
|
}
|
||||||
String obfuscatedValue = mObfuscator.obfuscate(value, key);
|
String obfuscatedValue = mObfuscator.obfuscate(value, key);
|
||||||
mEditor.putString(key, obfuscatedValue);
|
mEditor.putString(key, obfuscatedValue);
|
||||||
|
@ -75,6 +75,7 @@ public class ResponseData {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return TextUtils.join("|", new Object[] {
|
return TextUtils.join("|", new Object[] {
|
||||||
responseCode, nonce, packageName, versionCode,
|
responseCode, nonce, packageName, versionCode,
|
||||||
userId, timestamp });
|
userId, timestamp
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,4 +296,5 @@ public class ServerManagedPolicy implements Policy {
|
|||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -96,4 +96,5 @@ public class StrictPolicy implements Policy {
|
|||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,9 @@ package com.google.android.vending.licensing.util;
|
|||||||
* @version 1.3
|
* @version 1.3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
import com.godot.game.BuildConfig;
|
import com.godot.game.BuildConfig;
|
||||||
|
// -- GODOT end --
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base64 converter class. This code is not a full-blown MIME encoder;
|
* Base64 converter class. This code is not a full-blown MIME encoder;
|
||||||
@ -56,7 +58,8 @@ public class Base64 {
|
|||||||
/**
|
/**
|
||||||
* The 64 valid Base64 values.
|
* The 64 valid Base64 values.
|
||||||
*/
|
*/
|
||||||
private final static byte[] ALPHABET = { (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F',
|
private final static byte[] ALPHABET =
|
||||||
|
{(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F',
|
||||||
(byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K',
|
(byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K',
|
||||||
(byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
|
(byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
|
||||||
(byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
|
(byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
|
||||||
@ -73,7 +76,8 @@ public class Base64 {
|
|||||||
/**
|
/**
|
||||||
* The 64 valid web safe Base64 values.
|
* The 64 valid web safe Base64 values.
|
||||||
*/
|
*/
|
||||||
private final static byte[] WEBSAFE_ALPHABET = { (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F',
|
private final static byte[] WEBSAFE_ALPHABET =
|
||||||
|
{(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F',
|
||||||
(byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K',
|
(byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K',
|
||||||
(byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
|
(byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P',
|
||||||
(byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
|
(byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
|
||||||
@ -91,8 +95,7 @@ public class Base64 {
|
|||||||
* Translates a Base64 value to either its 6-bit reconstruction value
|
* Translates a Base64 value to either its 6-bit reconstruction value
|
||||||
* or a negative number indicating some other meaning.
|
* or a negative number indicating some other meaning.
|
||||||
**/
|
**/
|
||||||
private final static byte[] DECODABET = {
|
private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
|
||||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
|
|
||||||
-5, -5, // Whitespace: Tab and Linefeed
|
-5, -5, // Whitespace: Tab and Linefeed
|
||||||
-9, -9, // Decimal 11 - 12
|
-9, -9, // Decimal 11 - 12
|
||||||
-5, // Whitespace: Carriage Return
|
-5, // Whitespace: Carriage Return
|
||||||
@ -126,8 +129,8 @@ public class Base64 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** The web safe decodabet */
|
/** The web safe decodabet */
|
||||||
private final static byte[] WEBSAFE_DECODABET = {
|
private final static byte[] WEBSAFE_DECODABET =
|
||||||
-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
|
{-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8
|
||||||
-5, -5, // Whitespace: Tab and Linefeed
|
-5, -5, // Whitespace: Tab and Linefeed
|
||||||
-9, -9, // Decimal 11 - 12
|
-9, -9, // Decimal 11 - 12
|
||||||
-5, // Whitespace: Carriage Return
|
-5, // Whitespace: Carriage Return
|
||||||
@ -208,7 +211,9 @@ public class Base64 {
|
|||||||
// We have to shift left 24 in order to flush out the 1's that appear
|
// We have to shift left 24 in order to flush out the 1's that appear
|
||||||
// when Java treats a value as negative that is cast from a byte to an int.
|
// when Java treats a value as negative that is cast from a byte to an int.
|
||||||
int inBuff =
|
int inBuff =
|
||||||
(numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
|
(numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
|
||||||
|
| (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
|
||||||
|
| (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
|
||||||
|
|
||||||
switch (numSigBytes) {
|
switch (numSigBytes) {
|
||||||
case 3:
|
case 3:
|
||||||
@ -312,7 +317,9 @@ public class Base64 {
|
|||||||
// encode3to4( source, d + off, 3, outBuff, e, alphabet );
|
// encode3to4( source, d + off, 3, outBuff, e, alphabet );
|
||||||
// but inlined for faster encoding (~20% improvement)
|
// but inlined for faster encoding (~20% improvement)
|
||||||
int inBuff =
|
int inBuff =
|
||||||
((source[d + off] << 24) >>> 8) | ((source[d + 1 + off] << 24) >>> 16) | ((source[d + 2 + off] << 24) >>> 24);
|
((source[d + off] << 24) >>> 8)
|
||||||
|
| ((source[d + 1 + off] << 24) >>> 16)
|
||||||
|
| ((source[d + 2 + off] << 24) >>> 24);
|
||||||
outBuff[e] = alphabet[(inBuff >>> 18)];
|
outBuff[e] = alphabet[(inBuff >>> 18)];
|
||||||
outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f];
|
outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f];
|
||||||
outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f];
|
outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f];
|
||||||
@ -338,13 +345,18 @@ public class Base64 {
|
|||||||
e += 4;
|
e += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- GODOT start --
|
||||||
|
//assert (e == outBuff.length);
|
||||||
if (BuildConfig.DEBUG && e != outBuff.length)
|
if (BuildConfig.DEBUG && e != outBuff.length)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
|
// -- GODOT end --
|
||||||
return outBuff;
|
return outBuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ******** D E C O D I N G M E T H O D S ******** */
|
/* ******** D E C O D I N G M E T H O D S ******** */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes four bytes from array <var>source</var>
|
* Decodes four bytes from array <var>source</var>
|
||||||
* and writes the resulting bytes (up to three of them)
|
* and writes the resulting bytes (up to three of them)
|
||||||
@ -373,14 +385,17 @@ public class Base64 {
|
|||||||
// Example: Dk==
|
// Example: Dk==
|
||||||
if (source[srcOffset + 2] == EQUALS_SIGN) {
|
if (source[srcOffset + 2] == EQUALS_SIGN) {
|
||||||
int outBuff =
|
int outBuff =
|
||||||
((decodabet[source[srcOffset]] << 24) >>> 6) | ((decodabet[source[srcOffset + 1]] << 24) >>> 12);
|
((decodabet[source[srcOffset]] << 24) >>> 6)
|
||||||
|
| ((decodabet[source[srcOffset + 1]] << 24) >>> 12);
|
||||||
|
|
||||||
destination[destOffset] = (byte) (outBuff >>> 16);
|
destination[destOffset] = (byte) (outBuff >>> 16);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (source[srcOffset + 3] == EQUALS_SIGN) {
|
} else if (source[srcOffset + 3] == EQUALS_SIGN) {
|
||||||
// Example: DkL=
|
// Example: DkL=
|
||||||
int outBuff =
|
int outBuff =
|
||||||
((decodabet[source[srcOffset]] << 24) >>> 6) | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) | ((decodabet[source[srcOffset + 2]] << 24) >>> 18);
|
((decodabet[source[srcOffset]] << 24) >>> 6)
|
||||||
|
| ((decodabet[source[srcOffset + 1]] << 24) >>> 12)
|
||||||
|
| ((decodabet[source[srcOffset + 2]] << 24) >>> 18);
|
||||||
|
|
||||||
destination[destOffset] = (byte) (outBuff >>> 16);
|
destination[destOffset] = (byte) (outBuff >>> 16);
|
||||||
destination[destOffset + 1] = (byte) (outBuff >>> 8);
|
destination[destOffset + 1] = (byte) (outBuff >>> 8);
|
||||||
@ -388,7 +403,10 @@ public class Base64 {
|
|||||||
} else {
|
} else {
|
||||||
// Example: DkLE
|
// Example: DkLE
|
||||||
int outBuff =
|
int outBuff =
|
||||||
((decodabet[source[srcOffset]] << 24) >>> 6) | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) | ((decodabet[source[srcOffset + 3]] << 24) >>> 24);
|
((decodabet[source[srcOffset]] << 24) >>> 6)
|
||||||
|
| ((decodabet[source[srcOffset + 1]] << 24) >>> 12)
|
||||||
|
| ((decodabet[source[srcOffset + 2]] << 24) >>> 18)
|
||||||
|
| ((decodabet[source[srcOffset + 3]] << 24) >>> 24);
|
||||||
|
|
||||||
destination[destOffset] = (byte) (outBuff >> 16);
|
destination[destOffset] = (byte) (outBuff >> 16);
|
||||||
destination[destOffset + 1] = (byte) (outBuff >> 8);
|
destination[destOffset + 1] = (byte) (outBuff >> 8);
|
||||||
@ -397,6 +415,7 @@ public class Base64 {
|
|||||||
}
|
}
|
||||||
} // end decodeToBytes
|
} // end decodeToBytes
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes data from Base64 notation.
|
* Decodes data from Base64 notation.
|
||||||
*
|
*
|
||||||
@ -513,7 +532,8 @@ public class Base64 {
|
|||||||
if (b4Posn == 0 || b4Posn == 1) {
|
if (b4Posn == 0 || b4Posn == 1) {
|
||||||
throw new Base64DecoderException(
|
throw new Base64DecoderException(
|
||||||
"invalid padding byte '=' at byte offset " + i);
|
"invalid padding byte '=' at byte offset " + i);
|
||||||
} else if ((b4Posn == 3 && bytesLeft > 2) || (b4Posn == 4 && bytesLeft > 1)) {
|
} else if ((b4Posn == 3 && bytesLeft > 2)
|
||||||
|
|| (b4Posn == 4 && bytesLeft > 1)) {
|
||||||
throw new Base64DecoderException(
|
throw new Base64DecoderException(
|
||||||
"padding byte '=' falsely signals end of encoded value "
|
"padding byte '=' falsely signals end of encoded value "
|
||||||
+ "at offset " + i);
|
+ "at offset " + i);
|
||||||
@ -531,7 +551,8 @@ public class Base64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Base64DecoderException("Bad Base64 input character at " + i + ": " + source[i + off] + "(decimal)");
|
throw new Base64DecoderException("Bad Base64 input character at " + i
|
||||||
|
+ ": " + source[i + off] + "(decimal)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,7 +564,8 @@ public class Base64 {
|
|||||||
// padded with EQUALS_SIGN
|
// padded with EQUALS_SIGN
|
||||||
if (b4Posn != 0) {
|
if (b4Posn != 0) {
|
||||||
if (b4Posn == 1) {
|
if (b4Posn == 1) {
|
||||||
throw new Base64DecoderException("single trailing character at offset " + (len - 1));
|
throw new Base64DecoderException("single trailing character at offset "
|
||||||
|
+ (len - 1));
|
||||||
}
|
}
|
||||||
b4[b4Posn++] = EQUALS_SIGN;
|
b4[b4Posn++] = EQUALS_SIGN;
|
||||||
outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet);
|
outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet);
|
||||||
|
Loading…
Reference in New Issue
Block a user