Commit 253cd496 by Kim Jinsung

Merge branch 'features/1.2.363' into features/1.3.200

# Conflicts:
#	ABVJE_Res_Default_Android/res/values-ko/strings.xml
#	ABVJE_Res_Default_Android/res/values/strings.xml
#	ABVJE_UI_Android/src/jp/agentec/abook/abv/cl/util/BitmapUtil.java
parents c3e9f15b f443fdba
......@@ -16,8 +16,8 @@ public class MediaInfoJSON extends AbstractJSON {
public static final int BUTTON_TYPE = 1;
public static final int VIDEO_TYPE = 2;
public static final int MUSIC_TYPE = 3;
public static final int CHANGE_IMAGE_TYPE = 4;
public static final int CHANGE_VIDEO_TYPE = 5;
public static final int CHANGE_IMAGE_TYPE = 4; // 差し替え画像
public static final int CHANGE_VIDEO_TYPE = 5; // 差し替え動画
public static final int TRIGGER_TYPE = 6;
public static final int RICH_TEXT_TYPE = 7;
public static final int VIEW3D_TYPE = 8;
......
......@@ -156,4 +156,6 @@ public class ABookKeys {
public static final String APPROVAL_LIST = "approvalList";
public static final String PHASE_LIST = "phaseList";
public static final String PROCESS_LIST = "processList";
public static final String MAIL_TO_URL = "mailto";
}
......@@ -23,6 +23,8 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- GCM -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
......@@ -49,7 +51,8 @@
android:allowBackup="false"
tools:replace="android:allowBackup"
android:usesCleartextTraffic="true"
android:largeHeap="true" >
android:largeHeap="true"
android:requestLegacyExternalStorage="true">
<service android:name="jp.agentec.abook.abv.cl.push.ABVFcmListenerService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"></action>
......@@ -62,6 +65,11 @@
</intent-filter>
</service>
<service
android:name="jp.agentec.abook.abv.launcher.android.BackgroundDownloadService"
android:enabled="true"
android:exported="false" />
<receiver android:name="jp.agentec.abook.abv.launcher.android.OnAppDownloadReceiver">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" />
......
......@@ -17,11 +17,12 @@ dependencies {
}
android {
compileSdkVersion 26
compileSdkVersion 29
buildToolsVersion '28.0.3'
defaultConfig {
minSdkVersion 23
targetSdkVersion 29
multiDexEnabled true
// from gradle.properties
......@@ -133,6 +134,19 @@ android {
abiFilters "arm64-v8a", ""
}
}
x86 {
versionCode defaultConfig.versionCode + 2
ndk {
abiFilters "x86", ""
}
}
x86_64 {
versionCode defaultConfig.versionCode + 3
ndk {
abiFilters "x86_64", ""
}
}
}
}
}
......
......@@ -1482,5 +1482,6 @@
<!-- 連続作業 -->
<string name="msg_error_all_process_delete">全削除の送信に失敗しました。</string>
<string name="msg_ozd_file_could_not_opened">帳票ファイルを開くことができませんでした。</string>
</resources>
......@@ -1486,4 +1486,5 @@
<string name="msg_error_chat_room_sc_forbidden">사용자 정보를 확인할 수 없습니다. 다시 로그인하시기 바랍니다.</string>
<string name="msg_error_all_process_delete">모두 삭제 송신에 실패하였습니다.</string>
<string name="msg_error_already_exist_same_room">동일한 채팅방이 이미 존재합니다.</string>
<string name="msg_ozd_file_could_not_opened">장표 파일을 열 수 없습니다.</string>
</resources>
\ No newline at end of file
......@@ -1483,4 +1483,5 @@
<string name="msg_error_chat_room_sc_forbidden">Failed to authenticate. Please login again.</string>
<string name="msg_error_all_process_delete">Failed to send all deletes.</string>
<string name="msg_error_already_exist_same_room">Already exist same room.</string>
<string name="msg_ozd_file_could_not_opened">Report file could not opened.</string>
</resources>
......@@ -115,6 +115,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:inputType="text"
android:maxLines="1" />
<LinearLayout
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- ソースで文字列連結してアクセスしているためlintに引っかかってしまうので注意 -->
<integer name="marking_size_0">5</integer>
<integer name="marking_size_1">10</integer>
<integer name="marking_size_2">25</integer>
<integer name="marking_size_3">50</integer>
<integer name="marking_size_4">100</integer>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="cache_files" path="."/>
<external-path name="external_files" path="."/>
</paths>
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vending.billing;
import android.os.Bundle;
/**
* InAppBillingService is the service that provides in-app billing version 3 and beyond.
* This service provides the following features:
* 1. Provides a new API to get details of in-app items published for the app including
* price, type, title and description.
* 2. The purchase flow is synchronous and purchase information is available immediately
* after it completes.
* 3. Purchase information of in-app purchases is maintained within the Google Play system
* till the purchase is consumed.
* 4. An API to consume a purchase of an inapp item. All purchases of one-time
* in-app items are consumable and thereafter can be purchased again.
* 5. An API to get current purchases of the user immediately. This will not contain any
* consumed purchases.
*
* All calls will give a response code with the following possible values
* RESULT_OK = 0 - success
* RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog
* RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested
* RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase
* RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API
* RESULT_ERROR = 6 - Fatal error during the API action
* RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
* RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
*/
interface IInAppBillingService {
/**
* Checks support for the requested billing API version, package and in-app type.
* Minimum API version supported by this interface is 3.
* @param apiVersion the billing version which the app is using
* @param packageName the package name of the calling app
* @param type type of the in-app item being purchased "inapp" for one-time purchases
* and "subs" for subscription.
* @return RESULT_OK(0) on success, corresponding result code on failures
*/
int isBillingSupported(int apiVersion, String packageName, String type);
/**
* Provides details of a list of SKUs
* Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
* with a list JSON strings containing the productId, price, title and description.
* This API can be called with a maximum of 20 SKUs.
* @param apiVersion billing API version that the Third-party is using
* @param packageName the package name of the calling app
* @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "DETAILS_LIST" with a StringArrayList containing purchase information
* in JSON format similar to:
* '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00",
* "title : "Example Title", "description" : "This is an example description" }'
*/
Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
/**
* Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
* the type, a unique purchase token and an optional developer payload.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param sku the SKU of the in-app item as published in the developer console
* @param type the type of the in-app item ("inapp" for one-time purchases
* and "subs" for subscription).
* @param developerPayload optional argument to be sent back with the purchase information
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "BUY_INTENT" - PendingIntent to start the purchase flow
*
* The Pending intent should be launched with startIntentSenderForResult. When purchase flow
* has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
* If the purchase is successful, the result data will contain the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
* '{"orderId":"12999763169054705758.1371079406387615",
* "packageName":"com.example.app",
* "productId":"exampleSku",
* "purchaseTime":1345678900000,
* "purchaseToken" : "122333444455555",
* "developerPayload":"example developer payload" }'
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
* was signed with the private key of the developer
* TODO: change this to app-specific keys.
*/
Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
String developerPayload);
/**
* Returns the current SKUs owned by the user of the type and package name specified along with
* purchase information and a signature of the data to be validated.
* This will return all SKUs that have been purchased in V3 and managed items purchased using
* V1 and V2 that have not been consumed.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param type the type of the in-app items being requested
* ("inapp" for one-time purchases and "subs" for subscription).
* @param continuationToken to be set as null for the first call, if the number of owned
* skus are too many, a continuationToken is returned in the response bundle.
* This method can be called again with the continuation token to get the next set of
* owned skus.
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
* "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
* "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
* of the purchase information
* "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
* next set of in-app purchases. Only set if the
* user has more owned skus than the current list.
*/
Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken);
/**
* Consume the last purchase of the given SKU. This will result in this item being removed
* from all subsequent responses to getPurchases() and allow re-purchase of this item.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param purchaseToken token in the purchase information JSON that identifies the purchase
* to be consumed
* @return 0 if consumption succeeded. Appropriate error values for failures.
*/
int consumePurchase(int apiVersion, String packageName, String purchaseToken);
}
/* Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.agentec.abook.abv.cl.billing;
/**
* Exception thrown when something went wrong with in-app billing.
* An IabException has an associated IabResult (an error).
* To get the IAB result that caused this exception to be thrown,
* call {@link #getResult()}.
*/
public class IabException extends Exception {
IabResult mResult;
public IabException(IabResult r) {
this(r, null);
}
public IabException(int response, String message) {
this(new IabResult(response, message));
}
public IabException(IabResult r, Exception cause) {
super(r.getMessage(), cause);
mResult = r;
}
public IabException(int response, String message, Exception cause) {
this(new IabResult(response, message), cause);
}
/** Returns the IAB result (error) that this exception signals. */
public IabResult getResult() { return mResult; }
}
\ No newline at end of file
/* Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.agentec.abook.abv.cl.billing;
/**
* Represents the result of an in-app billing operation.
* A result is composed of a response code (an integer) and possibly a
* message (String). You can get those by calling
* {@link #getResponse} and {@link #getMessage()}, respectively. You
* can also inquire whether a result is a success or a failure by
* calling {@link #isSuccess()} and {@link #isFailure()}.
*/
public class IabResult {
int mResponse;
String mMessage;
public IabResult(int response, String message) {
mResponse = response;
if (message == null || message.trim().length() == 0) {
mMessage = IabHelper.getResponseDesc(response);
}
else {
mMessage = message + " (response: " + IabHelper.getResponseDesc(response) + ")";
}
}
public int getResponse() { return mResponse; }
public String getMessage() { return mMessage; }
public boolean isSuccess() { return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; }
public boolean isFailure() { return !isSuccess(); }
public String toString() { return "IabResult: " + getMessage(); }
}
/* Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.agentec.abook.abv.cl.billing;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Represents a block of information about in-app items.
* An Inventory is returned by such methods as {@link IabHelper#queryInventory}.
*/
public class Inventory {
Map<String,SkuDetails> mSkuMap = new HashMap<>();
Map<String,Purchase> mPurchaseMap = new HashMap<>();
Inventory() { }
/** Returns the listing details for an in-app product. */
public SkuDetails getSkuDetails(String sku) {
return mSkuMap.get(sku);
}
/** Returns purchase information for a given product, or null if there is no purchase. */
public Purchase getPurchase(String sku) {
return mPurchaseMap.get(sku);
}
/** Returns whether or not there exists a purchase of the given product. */
public boolean hasPurchase(String sku) {
return mPurchaseMap.containsKey(sku);
}
/** Return whether or not details about the given product are available. */
public boolean hasDetails(String sku) {
return mSkuMap.containsKey(sku);
}
/**
* Erase a purchase (locally) from the inventory, given its product ID. This just
* modifies the Inventory object locally and has no effect on the server! This is
* useful when you have an existing Inventory object which you know to be up to date,
* and you have just consumed an item successfully, which means that erasing its
* purchase data from the Inventory you already have is quicker than querying for
* a new Inventory.
*/
public void erasePurchase(String sku) {
if (mPurchaseMap.containsKey(sku)) {
mPurchaseMap.remove(sku);
}
}
/** Returns a list of all owned product IDs. */
List<String> getAllOwnedSkus() {
return new ArrayList<>(mPurchaseMap.keySet());
}
/** Returns a list of all owned product IDs of a given type */
List<String> getAllOwnedSkus(String itemType) {
List<String> result = new ArrayList<>();
for (Purchase p : mPurchaseMap.values()) {
if (p.getItemType().equals(itemType)) {
result.add(p.getSku());
}
}
return result;
}
/** Returns a list of all purchases. */
List<Purchase> getAllPurchases() {
return new ArrayList<>(mPurchaseMap.values());
}
void addSkuDetails(SkuDetails d) {
mSkuMap.put(d.getSku(), d);
}
void addPurchase(Purchase p) {
mPurchaseMap.put(p.getSku(), p);
}
}
/* Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.agentec.abook.abv.cl.billing;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Represents an in-app billing purchase.
*/
public class Purchase {
String mItemType; // ITEM_TYPE_INAPP or ITEM_TYPE_SUBS
String mOrderId;
String mPackageName;
String mSku;
long mPurchaseTime;
int mPurchaseState;
String mDeveloperPayload;
String mToken;
String mOriginalJson;
String mSignature;
public Purchase(String itemType, String jsonPurchaseInfo, String signature) throws JSONException {
mItemType = itemType;
mOriginalJson = jsonPurchaseInfo;
JSONObject o = new JSONObject(mOriginalJson);
mOrderId = o.optString("orderId");
mPackageName = o.optString("packageName");
mSku = o.optString("productId");
mPurchaseTime = o.optLong("purchaseTime");
mPurchaseState = o.optInt("purchaseState");
mDeveloperPayload = o.optString("developerPayload");
mToken = o.optString("token", o.optString("purchaseToken"));
mSignature = signature;
}
public String getItemType() { return mItemType; }
public String getOrderId() { return mOrderId; }
public String getPackageName() { return mPackageName; }
public String getSku() { return mSku; }
public long getPurchaseTime() { return mPurchaseTime; }
public int getPurchaseState() { return mPurchaseState; }
public String getDeveloperPayload() { return mDeveloperPayload; }
public String getToken() { return mToken; }
public String getOriginalJson() { return mOriginalJson; }
public String getSignature() { return mSignature; }
@Override
public String toString() { return "PurchaseInfo(type:" + mItemType + "):" + mOriginalJson; }
}
/* Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.agentec.abook.abv.cl.billing;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import android.text.TextUtils;
import android.util.Log;
/**
* Security-related methods. For a secure implementation, all of this code
* should be implemented on a server that communicates with the
* application on the device. For the sake of simplicity and clarity of this
* example, this code is included here and is executed on the device. If you
* must verify the purchases on the phone, you should obfuscate this code to
* make it harder for an attacker to replace the code with stubs that treat all
* purchases as verified.
*/
public class Security {
private static final String TAG = "IABUtil/Security";
private static final String KEY_FACTORY_ALGORITHM = "RSA";
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
/**
* Verifies that the data was signed with the given signature, and returns
* the verified purchase. The data is in JSON format and signed
* with a private key. The data also contains the PurchaseState
* and product ID of the purchase.
* @param base64PublicKey the base64-encoded public key to use for verifying.
* @param signedData the signed JSON string (signed, not encrypted)
* @param signature the signature for the data, signed with the private key
*/
public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
TextUtils.isEmpty(signature)) {
Log.e(TAG, "Purchase verification failed: missing data.");
return false;
}
PublicKey key = Security.generatePublicKey(base64PublicKey);
return Security.verify(key, signedData, signature);
}
/**
* Generates a PublicKey instance from a string containing the
* Base64-encoded public key.
*
* @param encodedPublicKey Base64-encoded public key
* @throws IllegalArgumentException if encodedPublicKey is invalid
*/
public static PublicKey generatePublicKey(String encodedPublicKey) {
try {
byte[] decodedKey = Base64.decode(encodedPublicKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeySpecException e) {
Log.e(TAG, "Invalid key specification.");
throw new IllegalArgumentException(e);
} catch (Base64DecoderException e) {
Log.e(TAG, "Base64 decoding failed.");
throw new IllegalArgumentException(e);
}
}
/**
* Verifies that the signature from the server matches the computed
* signature on the data. Returns true if the data is correctly signed.
*
* @param publicKey public key associated with the developer account
* @param signedData signed data from server
* @param signature server signature
* @return true if the data and signature match
*/
public static boolean verify(PublicKey publicKey, String signedData, String signature) {
Signature sig;
try {
sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
if (!sig.verify(Base64.decode(signature))) {
Log.e(TAG, "Signature verification failed.");
return false;
}
return true;
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "NoSuchAlgorithmException.");
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key specification.");
} catch (SignatureException e) {
Log.e(TAG, "Signature exception.");
} catch (Base64DecoderException e) {
Log.e(TAG, "Base64 decoding failed.");
}
return false;
}
}
/* Copyright (c) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jp.agentec.abook.abv.cl.billing;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Represents an in-app product's listing details.
*/
public class SkuDetails {
String mItemType;
String mSku;
String mType;
String mPrice;
String mTitle;
String mDescription;
String mJson;
public SkuDetails(String jsonSkuDetails) throws JSONException {
this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails);
}
public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
mItemType = itemType;
mJson = jsonSkuDetails;
JSONObject o = new JSONObject(mJson);
mSku = o.optString("productId");
mType = o.optString("type");
mPrice = o.optString("price");
mTitle = o.optString("title");
mDescription = o.optString("description");
}
public String getSku() { return mSku; }
public String getType() { return mType; }
public String getPrice() { return mPrice; }
public String getTitle() { return mTitle; }
public String getDescription() { return mDescription; }
@Override
public String toString() {
return "SkuDetails:" + mJson;
}
}
......@@ -451,5 +451,39 @@ public class BitmapUtil {
return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT);
}
/**
* アスペクト比を維持して、横に引き延ばしたBitmapを作成する
* @param filePath ファイルパス
* @param dispWidth 画面の幅
* @param dispHeight 画面の高さ
* @return リサイズしたBitmap
*/
public static Bitmap getResizedBitmap(String filePath, int dispWidth, int dispHeight) {
// Bitmap情報取得
BitmapFactory.Options options = BitmapUtil.getBitmapDimensions(filePath);
int bitmapWidth = options.outWidth;
int bitmpaHeight = options.outHeight;
// 変更するサイズを計算
int targetW;
int targetH;
if (bitmapWidth > bitmpaHeight) {
targetW = dispWidth;
targetH = (int) ((float) bitmpaHeight * (float) dispWidth / (float) bitmapWidth);
if (targetH > dispHeight) {
targetH = dispHeight;
targetW = (int) ((float) bitmapWidth * (float) dispHeight / (float) bitmpaHeight);
}
} else {
targetH = dispHeight;
targetW = (int) ((float) bitmapWidth * (float) dispHeight / (float) bitmpaHeight);
if (targetW > dispWidth) {
targetW = dispWidth;
targetH = (int) ((float) bitmpaHeight * (float) dispWidth / (float) bitmapWidth);
}
}
return BitmapUtil.getResizedBitmap(filePath, targetW, targetH, Config.RGB_565, true);
}
}
package jp.agentec.abook.abv.launcher.android;
import android.app.DownloadManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.support.v4.content.FileProvider;
import java.io.File;
import jp.agentec.abook.abv.bl.acms.type.AcmsApis;
import jp.agentec.abook.abv.bl.common.ABVEnvironment;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.data.ABVDataCache;
import jp.agentec.adf.util.DateTimeFormat;
import jp.agentec.adf.util.DateTimeUtil;
public class BackgroundDownloadService extends Service {
private final static String LOG_TAG = BackgroundDownloadService.class.getSimpleName();
private DownloadManager mDownloadManager;
private long mDownloadedFileID;
private String notificationChannelId;
private String notificationChannelIdLow;
private NotificationManager mNotificationManager;
@Override
public void onCreate() {
super.onCreate();
mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
notificationChannelId = getApplicationContext().getPackageName();
notificationChannelIdLow += ".Low";
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(notificationChannelId, getString(R.string.app_name), NotificationManager.IMPORTANCE_DEFAULT);
NotificationChannel notificationChannelLow = new NotificationChannel(notificationChannelIdLow, getString(R.string.app_name), NotificationManager.IMPORTANCE_LOW);
if (mNotificationManager != null) {
mNotificationManager.createNotificationChannel(notificationChannel);
mNotificationManager.createNotificationChannel(notificationChannelLow);
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
return START_STICKY;
}
BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
unregisterReceiver(this);
// Prevents the occasional unintentional call.
if (mDownloadedFileID == -1) {
return;
}
try {
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ABVEnvironment.APK_FILE_NAME);
if (file.exists()) {
Uri apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
Intent updateIntent = new Intent(Intent.ACTION_VIEW);
updateIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
updateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
updateIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Android10(Q)
if (Build.VERSION.SDK_INT >= 29) {
sendNotify(updateIntent, getString(R.string.app_update), false);
Logger.d(LOG_TAG, "sendNotify(updateIntent...).");
} else {
stopForeground(true);
startActivity(updateIntent);
Logger.d(LOG_TAG, "startActivity(fileIntent).");
}
} else {
sendNotify(intent, getString(R.string.DOWNLOAD_ERROR), false);
Logger.w(LOG_TAG, "sendNotify(intent...).");
}
} catch (Exception ex) {
sendNotify(intent, getString(R.string.DOWNLOAD_ERROR), false);
Logger.e(LOG_TAG, "startActivity(fileIntent).", ex);
} finally {
// Sets up the prevention of an unintentional call.
mDownloadedFileID = -1;
}
}
};
try {
ABVEnvironment abvEnvironment = ABVEnvironment.getInstance();
ABVDataCache dataCache = ABVDataCache.getInstance();
String currentDate = DateTimeUtil.toString(DateTimeUtil.getCurrentTimestamp(), DateTimeFormat.yyyyMMddHHmmss000_none);
String downloadUrl = AcmsApis.getDownloadApplicationFileUrl(abvEnvironment.acmsAddress, dataCache.getUrlPath(), dataCache.getMemberInfo().sid, currentDate);
Logger.d(LOG_TAG, "downloadUrl=%s", downloadUrl);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
request.setDescription("ABook Plus New Version File");
//LANケーブル接続のタイプ(ETHERNET TYPE)がないため、セットしない
//request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ABVEnvironment.APK_FILE_NAME);
Logger.d(LOG_TAG, "download local file=%s", file.getAbsolutePath());
File[] childs = file.getParentFile().listFiles();
if (childs != null && childs.length > 0 && childs[0].exists()) {
childs[0].delete();
}
request.setDestinationUri(Uri.fromFile(file));
// Registers function to listen to the completion of the download.
registerReceiver(onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
// Download 開始
Logger.d(LOG_TAG, "mDownloadManager.enqueue(request).");
mDownloadedFileID = mDownloadManager.enqueue(request);
//5秒以内にstartForegroundを呼ばないとクラッシュ
int uniqueId = (int) System.currentTimeMillis();
Notification notification = getNotification(uniqueId, intent, getString(R.string.download_start), true);
startForeground(uniqueId, notification);
} catch (Exception ex) {
Logger.e(LOG_TAG, "mDownloadManager.enqueue(request).", ex);
}
return super.onStartCommand(intent, flags, startId);
}
private void sendNotify(Intent intent, String message, boolean isImportanceLow) {
stopForeground(true);
int uniqueId = (int) System.currentTimeMillis();
Notification notification = getNotification(uniqueId, intent, message, isImportanceLow);
if (mNotificationManager != null) {
mNotificationManager.notify(uniqueId, notification);
Logger.d(LOG_TAG, "sendNotify()");
}
}
private Notification getNotification(int uniqueId, Intent intent, String message, boolean isImportanceLow) {
PendingIntent pendingIntent = PendingIntent.getActivity(this, uniqueId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return new Notification.Builder(this)
.setDefaults(Notification.DEFAULT_ALL)
.setSmallIcon(R.drawable.icon)
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentTitle(getString(R.string.app_name))
.setContentText(message)
.setContentIntent(pendingIntent)
.setChannelId(isImportanceLow ? notificationChannelIdLow : notificationChannelId)
.build();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
......@@ -6,7 +6,9 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import android.util.Log;
import android.widget.Toast;
......@@ -27,6 +29,10 @@ public class OnAppDownloadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return;
}
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
Logger.d("Download Complete ID : " + id);
......@@ -58,11 +64,25 @@ public class OnAppDownloadReceiver extends BroadcastReceiver {
if (downloadedTo != null && downloadedTo.toLowerCase().endsWith(".apk")) {
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ABVEnvironment.APK_FILE_NAME);
if (file.exists()) {
Intent i = new Intent(Intent.ACTION_VIEW);
// Activity以外からActivityを呼び出すためのフラグを設定
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
context.startActivity(i);
try {
// Android7でアップデート
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file);
Intent updateIntent = new Intent(Intent.ACTION_VIEW);
updateIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
updateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
updateIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(updateIntent);
} else {
Intent i = new Intent(Intent.ACTION_VIEW);
// Activity以外からActivityを呼び出すためのフラグを設定
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
context.startActivity(i);
}
} catch (Exception ex) {
Logger.e("OnAppDownloadReceiver.startActivity(fileIntent).", ex);
}
} else {
Toast.makeText(context, "No Exist APK File: ", Toast.LENGTH_LONG).show();
}
......
......@@ -12,6 +12,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
......@@ -48,6 +49,7 @@ import jp.agentec.abook.abv.bl.logic.UserAuthenticateLogic;
import jp.agentec.abook.abv.cl.environment.NetworkAdapter;
import jp.agentec.abook.abv.cl.push.FcmManager;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.launcher.android.BackgroundDownloadService;
import jp.agentec.abook.abv.launcher.android.OnAppDownloadReceiver;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType;
......@@ -255,26 +257,31 @@ public abstract class ABVNoAuthenticatedActivity extends ABVActivity {
public void onClick(DialogInterface dialog, int which) {
// バージョンアップフラグをON
PreferenceUtil.put(getApplicationContext(), AppDefType.DefPrefKey.APP_VERSIONUP_PROCESSING, true);
// Android8以上でバックグラウンドをフォアグラウンドで処理
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent serviceIntent = new Intent(mContext, BackgroundDownloadService.class);
startForegroundService(serviceIntent);
} else {
// Download 開始
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
String currentDate = DateTimeUtil.toString(DateTimeUtil.getCurrentTimestamp(), DateTimeFormat.yyyyMMddHHmmss000_none);
String downloadUrl = AcmsApis.getDownloadApplicationFileUrl(abvEnvironment.acmsAddress, dataCache.getUrlPath(), dataCache.getMemberInfo().sid, currentDate);
Logger.d(TAG, "downloadUrl=%s", downloadUrl);
Request request = new Request(Uri.parse(downloadUrl));
request.setDescription("ABook Plus New Version File");
//LANケーブル接続のタイプ(ETHERNET TYPE)がないため、セットしない
// request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ABVEnvironment.APK_FILE_NAME);
Logger.d(TAG, "download local file=%s", file.getAbsolutePath());
File[] childs = file.getParentFile().listFiles();
if (childs != null && childs.length > 0 && childs[0].exists()) {
childs[0].delete();
}
request.setDestinationUri(Uri.fromFile(file));
downloadManager.enqueue(request);
// Download 開始
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
String currentDate = DateTimeUtil.toString(DateTimeUtil.getCurrentTimestamp(), DateTimeFormat.yyyyMMddHHmmss000_none);
String downloadUrl = AcmsApis.getDownloadApplicationFileUrl(abvEnvironment.acmsAddress, dataCache.getUrlPath(), dataCache.getMemberInfo().sid, currentDate);
Logger.d(TAG, "downloadUrl=%s", downloadUrl);
Request request = new Request(Uri.parse(downloadUrl));
request.setDescription("ABook Plus New Version File");
//LANケーブル接続のタイプ(ETHERNET TYPE)がないため、セットしない
// request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ABVEnvironment.APK_FILE_NAME);
Logger.d(TAG, "download local file=%s", file.getAbsolutePath());
File[] childs = file.getParentFile().listFiles();
if (childs != null && childs.length > 0 && childs[0].exists()) {
childs[0].delete();
}
request.setDestinationUri(Uri.fromFile(file));
downloadManager.enqueue(request);
registerReceiver(new OnAppDownloadReceiver(), new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
registerReceiver(new OnAppDownloadReceiver(), new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
// アプリを閉じる
saveLeaveAppTime();
......
package jp.agentec.abook.abv.ui.home.activity;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.Context;
......@@ -11,6 +13,7 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
......@@ -42,8 +45,11 @@ import jp.agentec.abook.abv.bl.logic.AbstractLogic;
import jp.agentec.abook.abv.bl.logic.ContractLogic;
import jp.agentec.abook.abv.bl.logic.UserAuthenticateLogic;
import jp.agentec.abook.abv.cl.helper.ABVUncaughtExceptionHandler;
import jp.agentec.abook.abv.cl.helper.PreferenceHelper;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.cl.util.RawResourceUtil;
import jp.agentec.abook.abv.launcher.android.ABVApplication;
import jp.agentec.abook.abv.launcher.android.BackgroundDownloadService;
import jp.agentec.abook.abv.launcher.android.OnAppDownloadReceiver;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType;
......@@ -362,29 +368,35 @@ public class ABookSettingFragment extends PreferenceFragment {
dialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Download 開始
DownloadManager downloadManager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
String currentDate = DateTimeUtil.toString(DateTimeUtil.getCurrentTimestamp(), DateTimeFormat.yyyyMMddHHmmss000_none);
String downloadUrl = AcmsApis.getDownloadApplicationFileUrl(abvEnvironment.acmsAddress, dataCache.getUrlPath(), dataCache.getMemberInfo().sid, currentDate);
Logger.d(TAG, "downloadUrl=%s", downloadUrl);
Request request = new Request(Uri.parse(downloadUrl));
request.setDescription("ABook Plus New Version File");
//LANケーブル接続のタイプ(ETHERNET TYPE)がないため、セットしない
// request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
File file = new File(getActivity().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ABVEnvironment.APK_FILE_NAME);
Logger.d(TAG, "download local file=%s", file.getAbsolutePath());
File[] childs = file.getParentFile().listFiles();
if (childs != null && childs.length > 0 && childs[0].exists()) {
childs[0].delete();
}
request.setDestinationUri(Uri.fromFile(file));
if (downloadManager != null) {
downloadManager.enqueue(request);
}
getActivity().registerReceiver(new OnAppDownloadReceiver(), new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
// Android8以上でバックグラウンドをフォアグラウンドで処理
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Context context = getActivity().getApplicationContext();
Intent serviceIntent = new Intent(context, BackgroundDownloadService.class);
context.startForegroundService(serviceIntent);
} else {
// Download 開始
DownloadManager downloadManager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
String currentDate = DateTimeUtil.toString(DateTimeUtil.getCurrentTimestamp(), DateTimeFormat.yyyyMMddHHmmss000_none);
String downloadUrl = AcmsApis.getDownloadApplicationFileUrl(abvEnvironment.acmsAddress, dataCache.getUrlPath(), dataCache.getMemberInfo().sid, currentDate);
Logger.d(TAG, "downloadUrl=%s", downloadUrl);
Request request = new Request(Uri.parse(downloadUrl));
request.setDescription("ABook Plus New Version File");
//LANケーブル接続のタイプ(ETHERNET TYPE)がないため、セットしない
// request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
File file = new File(getActivity().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), ABVEnvironment.APK_FILE_NAME);
Logger.d(TAG, "download local file=%s", file.getAbsolutePath());
File[] childs = file.getParentFile().listFiles();
if (childs != null && childs.length > 0 && childs[0].exists()) {
childs[0].delete();
}
request.setDestinationUri(Uri.fromFile(file));
if (downloadManager != null) {
downloadManager.enqueue(request);
}
getActivity().registerReceiver(new OnAppDownloadReceiver(), new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
// アプリを閉じる
saveLeaveAppTime();
getActivity().moveTaskToBack(true);
......
......@@ -25,7 +25,6 @@ import jp.agentec.abook.abv.bl.common.exception.NetworkDisconnectedException;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType;
import jp.agentec.abook.abv.ui.common.util.PatternStringUtil;
import jp.agentec.abook.abv.ui.home.helper.ActivityHandlingHelper;
import jp.agentec.abook.abv.ui.home.helper.OzdFileHelper;
import jp.agentec.abook.abv.launcher.android.PDFFileProvider;
import jp.agentec.abook.abv.launcher.android.R;
......@@ -42,7 +41,6 @@ import oz.api.OZReportCommandListener;
import oz.api.OZReportViewer;
import static jp.agentec.abook.abv.cl.util.PreferenceUtil.getUserPref;
import static org.chromium.base.ContextUtils.getApplicationContext;
/**
* ABook Report(仮)ビュアー
......@@ -183,9 +181,7 @@ public class CheckOZDViewActivity extends ABVContentViewActivity {
public void onClick(View v) {
mButtonStatus = R.id.btn_close; // HTML側の分岐処理を行うため変数に値を渡す
doProcess(); // HTML側の処理を行う
if (mProcessKey != null && mPhaseNo != 0) { //連続作業用のOZView画面非表示
finishActivity();
}
finishActivity(); //OZView画面非表示
}
});
......@@ -245,7 +241,17 @@ public class CheckOZDViewActivity extends ABVContentViewActivity {
Logger.i(TAG,"********mOzFilePath = %s" + mOzFilePath);
if (mOzFilePath == null) {
ABVToastUtil.showMakeText(this, "ozFilePath null", Toast.LENGTH_LONG);
// 帳票ファイルが存在しない場合は、アラートを表示して前の画面に戻る
ABookAlertDialog alertDialog = AlertDialogUtil.createAlertDialog(this, getResources().getString(R.string.error));
alertDialog.setMessage(getResources().getString(R.string.msg_ozd_file_could_not_opened));
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ozdCancelProcess(); // 閉じる
finishActivity();
}
});
showAlertDialog(alertDialog);
return;
}
......
......@@ -564,6 +564,15 @@ public class ContentViewActivity extends ABVContentViewActivity {
Logger.d(TAG, "[onConfigurationChanged]:newConfig=" + newConfig);
mShowPageLayout.clear();
isVideoMax = false;
//埋め込み動画を停止する。
stopVideo();
//全画面動画を停止する。
if (fullVideoView != null) {
fullVideoView.close();
fullVideoView = null;
}
//noinspection VariableNotUsedInsideIf
if (mContentWrapLayout != null) {
removeViews();
......@@ -2820,7 +2829,52 @@ public class ContentViewActivity extends ABVContentViewActivity {
meetingManager.sendWs(MeetingManager.CMD_MOVEPAGE, getContentId(), jumpPage, null, null);
}
}
/**
* ページを削除・作成する(ハイライト表示のため、全てのページ再作成)
* 検索結果一覧からのページ選択時&ハイライトリセット時利用
* @param jumpPage ジャンプページNO
*/
private void addOrRemoveSearchPages(final int jumpPage) {
final int currentPage = mCurrentPageNumber;
mCurrentPageNumber = jumpPage;
//作成済みの現在&前後ページの場合、そのページ削除
if (Math.abs(jumpPage - currentPage) < 2) {
removePage(jumpPage);
}
//ジャンプページ作成
addPageView(jumpPage);
new Handler().postDelayed(new Runnable() {
@Override
public void run() { // ジャンプするページに応じて必要なだけ作成・削除する
//Jump以前の後ページ情報削除
if (currentPage != jumpPage) {
removePage(currentPage);
}
//Jump以前の後ページ情報削除
int nextPage = currentPage + 1;
if (jumpPage != nextPage) {
removePage(nextPage);
}
//Jump以前の前ページ情報削除
int prevPage = currentPage - 1;
if (jumpPage != prevPage) {
removePage(prevPage);
}
//jumpした前後ページ情報作成
addPageView(jumpPage + 1);
addPageView(jumpPage - 1);
}
}, 500);
}
/**
* ページを削除・作成する(現在・前後ページはしない)
* 検索結果以外のところからページジャンプ時利用
* @param jumpPage ジャンプページNO
*/
private void addOrRemovePages(final int jumpPage) {
final int currentPage = mCurrentPageNumber;
mCurrentPageNumber = jumpPage;
......@@ -2856,7 +2910,7 @@ public class ContentViewActivity extends ABVContentViewActivity {
// ページ別ログ
ContentLogUtil.getInstance().contentPageMove(contentId, readingLogId, mCurrentPageNumber, jumpPage);
addOrRemovePages(jumpPage);
addOrRemoveSearchPages(jumpPage);
mPageScrollView.setZoomingFlag(false);
mPageScrollView.post(new Runnable() {
@Override
......@@ -3693,6 +3747,8 @@ public class ContentViewActivity extends ABVContentViewActivity {
for (int i = 0; i < imagefile.size(); i++) {
intent_.putExtra("FILEPATH" + (i + 1), mContentDir + "/" + imagefile.get(i));
}
intent_.putExtra("imageSize", imagefile.size());
intent_.putExtra("Position", 0);
intent_.putExtra(ABookKeys.CONTENT_ID, getContentId());
intent_.putExtra("pageNumber", mCurrentPageNumber);
......
......@@ -291,6 +291,15 @@ public class HTMLWebViewActivity extends ParentWebViewActivity {
}
return true;
}
//mailtoスキームチェック
String mailUrl = ABookKeys.MAIL_TO_URL;
if (url.length() > mailUrl.length() && mailUrl.equals(url.substring(0, mailUrl.length()))) {
//メーラー起動
Intent intent = new Intent(Intent.ACTION_SENDTO,Uri.parse(url));
startActivity(intent);
return true;
}
return false;
}
......
......@@ -352,6 +352,14 @@ public class HTMLXWalkWebViewActivity extends ParentWebViewActivity {
} else if (url.startsWith(ABookKeys.PING)) {
return true;
}
//mailtoスキームチェック
String mailUrl = ABookKeys.MAIL_TO_URL;
if (url.length() > mailUrl.length() && mailUrl.equals(url.substring(0, mailUrl.length()))) {
//メーラー起動
Intent intent = new Intent(Intent.ACTION_SENDTO,Uri.parse(url));
startActivity(intent);
return true;
}
return false;
}
});
......
......@@ -8,6 +8,7 @@ import jp.agentec.abook.abv.cl.util.ContentLogUtil;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.activity.ABVContentViewActivity;
import jp.agentec.abook.abv.ui.common.util.ABVToastUtil;
import jp.agentec.abook.abv.ui.common.util.DisplayUtil;
import jp.agentec.abook.abv.ui.home.helper.ActivityHandlingHelper;
import jp.agentec.abook.abv.ui.viewer.view.ActionZoomLayout;
......@@ -16,7 +17,8 @@ import org.json.adf.JSONObject;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.net.Uri;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Gravity;
import android.view.KeyEvent;
......@@ -47,6 +49,10 @@ public class PreviewActivity extends ABVContentViewActivity {
private int mHistoryImageIndex[] = new int[2];
private int objectLogId;
// 実際に描画するBitmap
// Androidの仕様で100MB以上のBitmapは扱えないため、アスペクト比を保存した状態でリサイズしたもの)
private Bitmap FripperBitmap[];
@Override
public void onCreate(Bundle savedInstanceState) {
Logger.i(TAG, "onCreate");
......@@ -60,8 +66,7 @@ public class PreviewActivity extends ABVContentViewActivity {
LinearLayout.LayoutParams paramMain = new LinearLayout.LayoutParams(matchParent, matchParent);
mZoomLayout.addView(getLayoutInflater().inflate(R.layout.ac_preview, null), paramMain);
setContentView(mZoomLayout);
mMaxImg = 0;
// 画像数の取得
Intent intent = getIntent();
if (objectId != -1 || ABVEnvironment.getInstance().disableLogSend) {
......@@ -70,14 +75,7 @@ public class PreviewActivity extends ABVContentViewActivity {
}
objectLogId = intent.getIntExtra("objectLogId", -1);
mPosition = intent.getIntExtra("Position", 0);
for (int i = 0; i < 8; i++) {
if (intent.getStringExtra("FILEPATH" + (i + 1)) == null) {
break;
} else {
mMaxImg++;
}
}
mMaxImg = intent.getIntExtra("imageSize", 0);
mViewFlipper = (ViewFlipper) findViewById(R.id.viewFlipperPreview);
mLayoutThumbnail = (LinearLayout)findViewById(R.id.layoutThumbnail);
......@@ -96,6 +94,7 @@ public class PreviewActivity extends ABVContentViewActivity {
finishActivity();
return;
} else {
// 画面下の画像ボタン作成
float tmpDensity = getResources().getDisplayMetrics().density;
Bitmap resized = BitmapUtil.getResizedBitmap(mFilePath[i], (int)(50 * tmpDensity + 0.5f), (int)(50 * tmpDensity + 0.5f), Config.RGB_565, false);
imgBtn[i].setImageBitmap(resized);
......@@ -109,10 +108,13 @@ public class PreviewActivity extends ABVContentViewActivity {
mLayoutThumbnail.addView(imgBtn[i], paramThumbnail);
setBtnClick(imgBtn[i], i);
}
// 数が多い可能性もあるので、最初の1枚目のみBitmap作成してViewに追加する
ImageView flipperImageView = new ImageView(this);
flipperImageView.setScaleType(ScaleType.CENTER_INSIDE);
flipperImageView.setAdjustViewBounds(true);
flipperImageView.setImageURI(Uri.parse(mFilePath[0]));
FripperBitmap = new Bitmap[mMaxImg];
FripperBitmap[0] = resizeBitmap(mFilePath[0]);
flipperImageView.setImageBitmap(FripperBitmap[0]);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(wrapContent, wrapContent);
mFlipperLayout[0].addView(flipperImageView, param);
mHistoryImageIndex[0] = 1;
......@@ -228,7 +230,11 @@ public class PreviewActivity extends ABVContentViewActivity {
ImageView flipperImageView = new ImageView(this);
flipperImageView.setScaleType(ScaleType.FIT_CENTER); //CENTER_INSIDE
flipperImageView.setAdjustViewBounds(true);
flipperImageView.setImageURI(Uri.parse(mFilePath[index]));
if (FripperBitmap[index] == null) {
// 表示用Bitmapがない時は作成。
FripperBitmap[index] = resizeBitmap(mFilePath[index]);
}
flipperImageView.setImageBitmap(FripperBitmap[index]);
int MP = ViewGroup.LayoutParams.MATCH_PARENT;
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(MP, MP);
mFlipperLayout[index].removeAllViews();
......@@ -318,4 +324,42 @@ public class PreviewActivity extends ABVContentViewActivity {
super.onStop();
ContentLogUtil.getInstance().endObjectLog(getContentId(), objectLogId);
}
/**
* アスペクト比を維持して、横に引き延ばしたBitmapを作成する
* @param filePath ファイルパス
* @return リサイズしたBitmap
*/
private Bitmap resizeBitmap(String filePath) {
// ディスプレイ情報取得
Point point = DisplayUtil.getDisplaySize(this);
int dispWidth = point.x;
int dispHeight = point.y;
// Bitmap情報取得
BitmapFactory.Options options = BitmapUtil.getBitmapDimensions(filePath);
int bitmapWidth = options.outWidth;
int bitmpaHeight = options.outHeight;
// 変更するサイズを計算
int targetW;
int targetH;
if (bitmapWidth > bitmpaHeight) {
targetW = dispWidth;
targetH = (int) ((float) bitmpaHeight * (float) dispWidth / (float) bitmapWidth);
if (targetH > dispHeight) {
targetH = dispHeight;
targetW = (int) ((float) bitmapWidth * (float) dispHeight / (float) bitmpaHeight);
}
} else {
targetH = dispHeight;
targetW = (int) ((float) bitmapWidth * (float) dispHeight / (float) bitmpaHeight);
if (targetW > dispWidth) {
targetW = dispWidth;
targetH = (int) ((float) bitmpaHeight * (float) dispWidth / (float) bitmapWidth);
}
}
return BitmapUtil.getResizedBitmap(filePath, targetW, targetH, Config.RGB_565, true);
}
}
\ No newline at end of file
......@@ -154,7 +154,10 @@ public class EnqueteLayout extends RelativeLayout {
return false;
}
});
if (Build.VERSION.SDK_INT >= 29) {
mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
mWebView.loadUrl(htmlPath);
}
......
......@@ -5,6 +5,7 @@ import android.content.Context;
import android.graphics.Color;
import android.graphics.PointF;
import android.net.Uri;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
......@@ -58,7 +59,7 @@ public class OperationTaskLayout extends RelativeLayout {
private static final int FINISHED_STATUS = 999;
private WebView mWebView = null;
private EnqueteWebView mWebView = null;
public ZoomRelativeLayout currentLayout;
public OperationTaskDto currentTaskDto;
......@@ -100,6 +101,10 @@ public class OperationTaskLayout extends RelativeLayout {
// mWebView.loadDataWithBaseURL("", url2, "text/html", "UTF-8", "");
settings.setAllowFileAccessFromFileURLs(true); //Android7利用で警告ダイヤログ表示問題対応
mWebView.setAlpha((int) (255 * 1.0f));
if (Build.VERSION.SDK_INT >= 29) {
mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
mWebView.loadUrl(linkUrl);
RelativeLayout.LayoutParams params;
......
......@@ -844,19 +844,6 @@ public class ZoomRelativeLayout extends RelativeLayout {
//if (!mScaleDetector.isInProgress() && pageScrollView.isScrollable()) {
//스크롤 픽스 상태였을 경우 메모 추가가 안 되어서
if (!mScaleDetector.isInProgress() && mPageScrollView.isMemocheck()) {
// MemoAction
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof Action3DImageView) {
Action3DImageView a3dv = (Action3DImageView)child;
if (a3dv.getEventFlg() == true) {
// 3Dモードの場合は長押しメモ処理を行わない
return;
}
}
}
// PDF画面外側をタッチしているかチェック
mPdfScale = Math.min(getWidth() / (float)mPdfSize.width, getHeight() / (float)mPdfSize.height);
float marginX = getMarginX(mPdfScale);
......@@ -868,7 +855,26 @@ public class ZoomRelativeLayout extends RelativeLayout {
return;
}
if (mContentDto != null) {
showMemoMenu(x, y);
//Android10以上ではAction3DImageViewの長押しイベントより、ZoomRelativeLayoutの長押しイベントが先に呼ばれる問題対応
//Androidバージョンチェックせずに全部対象とする。(0.3秒後にメモ表示するように修正)
getHandler().postDelayed(new Runnable() {
@Override
public void run() {
//3DView表示領域チェック
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child instanceof Action3DImageView) {
Action3DImageView a3dv = (Action3DImageView)child;
if (a3dv.getEventFlg() == true) {
// 3Dモードの場合は長押しメモ処理を行わない
Logger.d(TAG, "a3dv.getEventFlg() == true");
return;
}
}
}
showMemoMenu(x, y);
}
}, 300);
}
}
......
package jp.agentec.abook.abv.ui.viewer.view.action;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.cl.util.BitmapUtil;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.util.DisplayUtil;
import jp.agentec.abook.abv.ui.viewer.view.ActionImageView;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
......@@ -99,10 +102,14 @@ public class ImageChangeAction {
//noinspection deprecation(API16から非推奨になった。無視)
imgView.setBackgroundDrawable(null); //半透明表示
Bitmap myBitmap = BitmapFactory.decodeFile(imgfile);
imgView.setImageBitmap(myBitmap);
// イメージをアスペクト比を無視してリサイズしているため、処理をコメントアウトする
// Bitmap resized = BitmapUtil.getResizedBitmap(imgfile, w, h, Config.RGB_565, false); //イメージサイズをリサイズする
// imgView.setImageBitmap(resized);
// ディスプレイ情報取得して、アクセプト比を維持してリサイズ
Point point = DisplayUtil.getDisplaySize(context);
int dispWidth = point.x;
int dispHeight = point.y;
Bitmap resized = BitmapUtil.getResizedBitmap(imgfile,dispWidth,dispHeight);
imgView.setImageBitmap(resized);
layout.addView(imgView, param1);
return imgView;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment