Commit b2c82cf4 by yuichiro ogawa

Merge remote-tracking branch 'origin/features/1.2.300' into features/1.2.0_ogawa-y

parents 4ae9c18a 62dd14c1
......@@ -14,24 +14,24 @@ import java.util.Observer;
import jp.agentec.abook.abv.bl.acms.client.json.AcmsBooleanResultJSON;
import jp.agentec.abook.abv.bl.acms.client.json.AcmsCommonJSON;
import jp.agentec.abook.abv.bl.acms.client.json.AcmsMessageJSON;
import jp.agentec.abook.abv.bl.acms.client.json.ApertureMasterDataJSON;
import jp.agentec.abook.abv.bl.acms.client.json.AppLatestVersionJSON;
import jp.agentec.abook.abv.bl.acms.client.json.AuthLevelJSON;
import jp.agentec.abook.abv.bl.acms.client.json.CategoriesJSON;
import jp.agentec.abook.abv.bl.acms.client.json.ContentCheckDeliverableJSON;
import jp.agentec.abook.abv.bl.acms.client.json.ContentVersionsJSON;
import jp.agentec.abook.abv.bl.acms.client.json.FixPushMessageJSON;
import jp.agentec.abook.abv.bl.acms.client.json.GroupsJSON;
import jp.agentec.abook.abv.bl.acms.client.json.LogSendFlagJSON;
import jp.agentec.abook.abv.bl.acms.client.json.NewAppStoreLoginJSON;
import jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON;
import jp.agentec.abook.abv.bl.acms.client.json.OperationGroupMasterJSON;
import jp.agentec.abook.abv.bl.acms.client.json.ApertureMasterDataJSON;
import jp.agentec.abook.abv.bl.acms.client.json.OperationListJSON;
import jp.agentec.abook.abv.bl.acms.client.json.RequirePasswordChangeJSON;
import jp.agentec.abook.abv.bl.acms.client.json.ResultJSON;
import jp.agentec.abook.abv.bl.acms.client.json.SceneEntryJSON;
import jp.agentec.abook.abv.bl.acms.client.json.ServerTimeZoneJSON;
import jp.agentec.abook.abv.bl.acms.client.json.ServiceOptionsJSON;
import jp.agentec.abook.abv.bl.acms.client.json.FixPushMessageJSON;
import jp.agentec.abook.abv.bl.acms.client.json.OperationDataJSON;
import jp.agentec.abook.abv.bl.acms.client.json.OperationListJSON;
import jp.agentec.abook.abv.bl.acms.client.json.SceneEntryJSON;
import jp.agentec.abook.abv.bl.acms.client.json.WorkerGroupJSON;
import jp.agentec.abook.abv.bl.acms.client.parameters.AbstractAcmsLoginParameters;
import jp.agentec.abook.abv.bl.acms.client.parameters.AcmsContentParameters;
......@@ -68,7 +68,6 @@ import jp.agentec.abook.abv.bl.common.exception.JSONValidationException;
import jp.agentec.abook.abv.bl.common.exception.NetworkDisconnectedException;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.common.nw.NetworkAdapter;
import jp.agentec.abook.abv.bl.common.util.SecurityUtil;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.MemberInfoDao;
import jp.agentec.abook.abv.bl.dto.CategoryDto;
......@@ -200,9 +199,8 @@ public class AcmsClient implements AcmsClientResponseListener {
if (json.result) {
dto.invalidPasswordCount = (short) 0;
dto.lastLoginDate = json.presentTime;
// パスワードは暗号化して保存する。
dto.password = SecurityUtil.encryptPassword(param.getPassword(), ABVEnvironment.LoginPasswordAESKey);
//パスワードは暗号化して保存する。
dto.password = param.getPassword();
} else {
if (json.requirePasswordChange == RequirePasswordChangeCode.FirstTime
|| json.requirePasswordChange == RequirePasswordChangeCode.Required) {
......@@ -618,21 +616,19 @@ public class AcmsClient implements AcmsClientResponseListener {
/**
* パノラマで使用するシーンを登録
* @param sid
* @param contentId
* @param FormFile シーンで使用する画像
* @return
* @throws IOException
* @throws AcmsException
*/
public SceneEntryJSON sceneEntry(String sid, Long contentId, File FormFile) throws IOException, AcmsException, NetworkDisconnectedException {
public SceneEntryJSON sceneEntry(String sid, File FormFile) throws IOException, AcmsException, NetworkDisconnectedException {
if (networkAdapter != null && !networkAdapter.isNetworkConnected()) { // NWのチェック
throw new NetworkDisconnectedException();
}
String apiUrl = AcmsApis.getApiUrl(env.acmsAddress, urlPath, AcmsApis.ApiSceneEntry);
HttpMultipart part1 = new HttpMultipart(ABookKeys.SID, sid);
HttpMultipart part2 = new HttpMultipart(ABookKeys.CONTENT_ID, StringUtil.toString(contentId));
HttpMultipart part3 = new HttpMultipart(ABookKeys.FORM_FILE, FormFile);
HttpResponse result = HttpRequestSender.post(apiUrl, new HttpMultipart[]{part1, part2, part3});
HttpMultipart part2 = new HttpMultipart(ABookKeys.FORM_FILE, FormFile);
HttpResponse result = HttpRequestSender.post(apiUrl, new HttpMultipart[]{part1, part2});
SceneEntryJSON json = new SceneEntryJSON(result.httpResponseBody);
if (json.httpStatus != 200) {
if (json.errorMessage != null) {
......
......@@ -152,5 +152,11 @@ public interface ServiceOption {
* 作業種別:N(通常)、Y(作業種別毎に絞り込み可能なボタン・画面表示)
*/
int OperationGroupMaster = 175;
/**
* ユーザパスワードソルト付加
* 利用しない:N(通常)、利用する:Y
*/
int AddUserPasswordSalt = 181;
}
}
\ No newline at end of file
......@@ -168,4 +168,10 @@ public class Constant {
int NO = 0;
int YES = 1;
}
//Wifiスキャンタイプ
public interface WifiScanType {
int CloseCameraActivity = 0;
int ThetaConnectError = 1;
}
}
......@@ -129,4 +129,11 @@ public class ABookKeys {
public static final String CMD_EDIT_ATTACHED = "editAttached"; //再編集のためのcmdパラメタ
public static final String EDITABLE = "editable"; //commonAttachedDataUrl()で編集可否を判別するパラメタをWebからもらう。
public static final String FILE_PATH = "filePath"; //再編集する場合、クリックしたイマージのパスのパラメタ
public static final String BASE_CONTENT_REGISTER = "BaseContentRegister";
//THETA端末関連
public static final String THETA_FILE_ID = "OBJECT_ID";
public static final String THETA_THUMBNAIL = "THUMBNAIL";
public static final String THETA_OLD_VERSION_FLG = "thetaOldVersionFlg"; //true:API2.0利用、false:API2.1利用
public static final String THETA_LIST_ACTIVITY_FLG = "thetaListActivityFlg";
}
package jp.agentec.abook.abv.bl.common.constant;
public class ABookValues {
public static final String THETA_IP_ADDRESS = "192.168.1.1";
public static final String THETA_MODEL_NAME_THETA = "THETA";
public static final String THETA_MODEL_NAME_THETA_SC = "RICOH THETA SC";
public static final String THETA_MODEL_NAME_THETA_S = "RICOH THETA S";
public static final String SUCCESS = "success";
public static final String FAIL = "fail";
}
package jp.agentec.abook.abv.bl.common.util;
import org.apache.commons.codec.binary.Base64;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.apache.commons.codec.binary.Base64;
import jp.agentec.abook.abv.bl.common.ABVEnvironment;
import jp.agentec.abook.abv.bl.common.exception.ABVRuntimeException;
import jp.agentec.abook.abv.bl.data.ABVDataCache;
import jp.agentec.adf.security.cryptography.AES;
import jp.agentec.adf.security.cryptography.MD5;
import jp.agentec.adf.util.StringUtil;
......@@ -249,4 +252,52 @@ public class SecurityUtil {
}
}
/**
* @version 1.2.300
* サービスオプション「ユーザパスワードソルト付加」がtrueの場合、
* パスワードとログインIDをソルトしてから結合し、MD5値を返却します
* falseの場合、既存暗号化パスワード返す。
*
* @param password 通常パスワード
* @param loginId 通常ログインID
* @return MD5化されたパスワード(password+salt)
*/
public static String getEncriptPassword(String password, String loginId) {
//新しいパスワード暗号化
if (ABVDataCache.getInstance().serviceOption.isAddUserPasswordSalt()) {
String salt = getHashedSalt(loginId);
try {
return MD5.getMd5Hash(password + salt);
} catch (NoSuchAlgorithmException e) {
throw new ABVRuntimeException(e);
}
}
//既存パスワード暗号化
return encryptPassword(password, ABVEnvironment.LoginPasswordAESKey);
}
/**
* ユーザID(ソルト)をハッシュ化して返却します
* ※ハッシュアルゴリズムはSHA-256を使用
*
* @param salt ソルト(ユーザID)
* @return ハッシュ化された文字列(大文字)
*
*/
private static String getHashedSalt(String salt) {
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
messageDigest.update(salt.getBytes());
byte[] encryptSalt = messageDigest.digest();
StringBuilder sb = new StringBuilder(64);
for (byte b : encryptSalt) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString().toUpperCase();
}
}
......@@ -337,6 +337,15 @@ public class ABVDataCache {
}
/**
* @version 1.2.300
* サービスオプション(ユーザパスワードソルト付加)返す
* @return true:利用する, false:利用しない
*/
public boolean isAddUserPasswordSalt() {
return isServiceOptionEnable(ServiceOptionId.AddUserPasswordSalt);
}
/**
* 作業種別のサービスオプション情報取得
* @return
*/
......
......@@ -171,6 +171,8 @@ public class ContentDownloader {
Logger.e(TAG, "execKickTask encountered an exception.", e);
} catch (NetworkDisconnectedException e) {
Logger.e(TAG, "execKickTask encountered an exception.", e);
} catch (Exception e) {
Logger.e(TAG, "execKickTask encountered an exception.", e);
} finally {
isKickTask = false;
}
......@@ -178,7 +180,7 @@ public class ContentDownloader {
});
}
private void execKickTask() throws AcmsException, NetworkDisconnectedException {
private void execKickTask() throws AcmsException, NetworkDisconnectedException, Exception {
autoPaused = false;
if (Logger.isDebugEnabled()) {
Logger.d(TAG, "downloaderMap %s", getDownloadMapForDebug());
......@@ -622,7 +624,7 @@ public class ContentDownloader {
* @throws AcmsException
* @throws NetworkDisconnectedException
*/
private void startDownload(ContentDto contentDto) throws AcmsException, NetworkDisconnectedException {
private void startDownload(ContentDto contentDto) throws AcmsException, NetworkDisconnectedException, Exception {
contentDto.status = DownloadStatusType.Downloading.type();
contentDto.resourcePath = ABVEnvironment.getInstance().getContentResourcesDirectoryPath(contentDto.contentId, false);
contentDto.downloadStartDate = DateTimeUtil.getCurrentDate();
......@@ -691,7 +693,7 @@ public class ContentDownloader {
return downloadUrl;
}
private GetContentParameters getContentParameter(ContentDto contentDto) {
private GetContentParameters getContentParameter(ContentDto contentDto) throws NullPointerException {
GetContentParameters param;
param = new GetContentParameters(contentDto.contentId, cache.getMemberInfo().sid, ContentZipType.ContentDownload);
return param;
......
......@@ -135,6 +135,11 @@ public class ContentReadingLogLogic extends AbstractLogic {
*/
public synchronized void batchSendReadingLog() {
List<ContentReadingLogDto> list = contentReadingLogDao.getContentReadLogs();
//コンテンツ閲覧画面からアプリロック発生した場合、cache情報かクリアされ、getMemberInfoがnullになる問題対応
//getMemberInfoがnullの場合、閲覧ログ送信しないように修正
if (cache.getMemberInfo() == null) {
return;
}
try {
for (ContentReadingLogDto logDto : list) {
......
......@@ -1380,12 +1380,11 @@ public class OperationLogic extends AbstractLogic {
/**
* シーンの登録
* @param file
* @param contentId
* @throws IOException
* @throws AcmsException
*/
public Integer sendScene(File file, Long contentId) throws IOException, AcmsException, NetworkDisconnectedException {
SceneEntryJSON json = AcmsClient.getInstance(cache.getUrlPath(), networkAdapter).sceneEntry(cache.getMemberInfo().sid, contentId, file);
public Integer sendScene(File file) throws IOException, AcmsException, NetworkDisconnectedException {
SceneEntryJSON json = AcmsClient.getInstance(cache.getUrlPath(), networkAdapter).sceneEntry(cache.getMemberInfo().sid, file);
return json.resourceId;
}
......
......@@ -294,7 +294,7 @@ public class UserAuthenticateLogic extends AbstractLogic {
if (StringUtil.isNullOrWhiteSpace(password)) {
throw new IllegalArgumentException("argument oldPassword and newPassword not allowed null or white space. ");
}
String encryptedPassword = SecurityUtil.encryptPassword(password, ABVEnvironment.LoginPasswordAESKey);
String encryptedPassword = SecurityUtil.getEncriptPassword(password, dto.loginId);
result = dto.password.equals(encryptedPassword);
} else {
throw new ABVRuntimeException(ABVExceptionCode.C_E_SECURITY_1004);
......@@ -304,7 +304,7 @@ public class UserAuthenticateLogic extends AbstractLogic {
}
public boolean checkPassword(MemberInfoDto dto, String password) {
String encryptedPassword = SecurityUtil.encryptPassword(password, ABVEnvironment.LoginPasswordAESKey);
String encryptedPassword = SecurityUtil.getEncriptPassword(password, dto.loginId);
return dto.password.equals(encryptedPassword);
}
......@@ -327,7 +327,7 @@ public class UserAuthenticateLogic extends AbstractLogic {
throw new IllegalArgumentException("argument oldPassword and newPassword not allowed null or white space. ");
}
String oldEncryptedPassword = SecurityUtil.encryptPassword(oldPassword, ABVEnvironment.LoginPasswordAESKey);
String oldEncryptedPassword = SecurityUtil.getEncriptPassword(oldPassword, dto.loginId);
String newEncryptedPassword;
if (!dto.password.equals(oldEncryptedPassword)) {
......@@ -340,7 +340,7 @@ public class UserAuthenticateLogic extends AbstractLogic {
result = AcmsClient.getInstance(cache.getUrlPath(), networkAdapter).passwordChange(param);
if (result) {
newEncryptedPassword = SecurityUtil.encryptPassword(newPassword, ABVEnvironment.LoginPasswordAESKey);
newEncryptedPassword = SecurityUtil.getEncriptPassword(newPassword, dto.loginId);
dto.password = newEncryptedPassword;
dto.loginStatus = LoginStatus.LoggedIn.statusCode();
......
......@@ -182,6 +182,25 @@
android:label="LoginPasswordChangeActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
</activity>
<activity
android:name="jp.agentec.abook.abv.ui.viewer.activity.DeviceImageListActivityDialog"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="DeviceImageListActivity"
android:theme="@style/Theme_Contentdetailview" />
<activity android:name="jp.agentec.abook.abv.ui.viewer.activity.DeviceImageListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>
<activity android:name="jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaCameraActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>
<activity android:name="jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaImageListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>
<activity android:name="jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaImagePreviewActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>
<activity android:name="jp.agentec.abook.abv.ui.home.activity.ABookSettingActivity" android:theme="@android:style/Theme.NoTitleBar"/>
<activity android:name="jp.agentec.abook.abv.ui.home.activity.ChangePasswordActivity" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>
<activity android:name="jp.agentec.abook.abv.ui.home.activity.ChangePasswordActivityDialog" android:theme="@style/Theme.MyTheme.ModalDialog"/>
......
......@@ -360,7 +360,7 @@
<string name="label_entry">登録</string>
<string name="label_base_file">ベースファイル</string>
<string name="select_image">画像選択</string>
<string name="error_msg_open_pano_edit">他の端末で資料が編集中の為、編集できません(%1$s)</string>
<string name="error_msg_open_pano_edit">他の端末で資料が編集中の為、編集できません。</string>
<string name="P001">資料名に半角カタカナは使用できません。</string>
<string name="P002">既に資料が登録されています。</string>
......@@ -580,7 +580,7 @@
<string name="label_entry_1">登録(1)</string>
<string name="label_base_file_1">ベースファイル(1)</string>
<string name="select_image_1">画像選択(1)</string>
<string name="error_msg_open_pano_edit_1">他の端末で資料が編集中の為、編集できません(%1$s)。(1)</string>
<string name="error_msg_open_pano_edit_1">他の端末で資料が編集中の為、編集できません。(1)</string>
<string name="P001_1">資料名に半角カタカナは使用できません。(1)</string>
<string name="P002_1">既に資料が登録されています。(1)</string>
......@@ -756,7 +756,7 @@
<string name="label_entry_2">登録(2)</string>
<string name="label_base_file_2">ベースファイル(2)</string>
<string name="select_image_2">画像選択(2)</string>
<string name="error_msg_open_pano_edit_2">他の端末で資料が編集中の為、編集できません(%1$s)。(2)</string>
<string name="error_msg_open_pano_edit_2">他の端末で資料が編集中の為、編集できません。(2)</string>
<string name="P001_2">資料名に半角カタカナは使用できません。(2)</string>
<string name="P002_2">既に資料が登録されています。(2)</string>
......@@ -932,7 +932,7 @@
<string name="label_entry_3">登録(3)</string>
<string name="label_base_file_3">ベースファイル(3)</string>
<string name="select_image_3">画像選択(3)</string>
<string name="error_msg_open_pano_edit_3">他の端末で資料が編集中の為、編集できません(%1$s)。(3)</string>
<string name="error_msg_open_pano_edit_3">他の端末で資料が編集中の為、編集できません。(3)</string>
<string name="P001_3">資料名に半角カタカナは使用できません。(3)</string>
<string name="P002_3">既に資料が登録されています。(3)</string>
......@@ -1108,7 +1108,7 @@
<string name="label_entry_4">登録(4)</string>
<string name="label_base_file_4">ベースファイル(4)</string>
<string name="select_image_4">画像選択(4)</string>
<string name="error_msg_open_pano_edit_4">他の端末で資料が編集中の為、編集できません(%1$s)。(4)</string>
<string name="error_msg_open_pano_edit_4">他の端末で資料が編集中の為、編集できません。(4)</string>
<string name="P001_4">資料名に半角カタカナは使用できません。(4)</string>
<string name="P002_4">既に資料が登録されています。(4)</string>
......@@ -1284,7 +1284,7 @@
<string name="label_entry_5">登録(5)</string>
<string name="label_base_file_5">ベースファイル(5)</string>
<string name="select_image_5">画像選択(5)</string>
<string name="error_msg_open_pano_edit_5">他の端末で資料が編集中の為、編集できません(%1$s)。(5)</string>
<string name="error_msg_open_pano_edit_5">他の端末で資料が編集中の為、編集できません。(5)</string>
<string name="P001_5">資料名に半角カタカナは使用できません。(5)</string>
<string name="P002_5">既に資料が登録されています。(5)</string>
......@@ -1420,4 +1420,44 @@
<string name="msg_confirm_close_edit_page">編集を終了しますか?\n(保存されていない変更は破棄されます。)</string>
<string name="msg_error_edit_page_save">ファイルの保存中に予想以外のエラーが発生しました。\n編集画面を終了します。</string>
<string name="msg_error_edit_page_open">編集画面の表示に失敗しました。</string>
<!-- ABookCheck 1.2.300 -->
<string name="title_scene_image_select">シーン画像選択</string>
<string name="msg_image_select_max_count_over">シーン画像の選択可能な最大数は%s個までです。</string>
<string name="msg_image_select_send_comfirm">選択したシーン画像を登録しますか?</string>
<string name="msg_image_select_send_success">シーン画像の登録に成功しました。</string>
<string name="msg_image_select_send_fail_retry">シーン画像の登録に失敗しました。再度登録処理を実行しますか?</string>
<string name="msg_access_registing">登録中</string>
<string name="title_theta_camera">THETAカメラ</string>
<string name="title_theta_camera_shoot">撮影</string>
<string name="title_theta_library">THETAライブラリ</string>
<string name="title_theta_image_preview">THETAプレビュー</string>
<string name="title_theta_connect">カメラ選択</string>
<string name="msg_wifi_connecting">Wi-Fi接続中...</string>
<string name="msg_fail_connect_theta_wifi">THETAカメラへの接続に失敗しました。THETAカメラのWi-Fi設定を確認してください。</string>
<string name="title_theta_wifi_saved">登録済みの端末</string>
<string name="title_theta_wifi_not_saved">未登録の端末</string>
<string name="title_theta_image_save">転送</string>
<string name="msg_theta_image_send_confirm">この画像を転送しますか?</string>
<string name="msg_theta_image_send_success">画像転送に成功しました。</string>
<string name="msg_theta_image_send_fail">画像転送に失敗しました。\nWi-Fi接続状態を確認してください。</string>
<string name="msg_theta_image_delete_confirm">この画像を削除しますか?</string>
<string name="msg_theta_image_delete_success">画像削除に成功しました。</string>
<string name="msg_theta_image_delete_fail">画像削除に失敗しました。\nWi-Fi接続状態を確認してください。</string>
<string name="msg_theta_image_load_fail">画像情報取得に失敗しました。\nWi-Fi接続状態を確認してください。</string>
<string name="msg_deleting">削除中...</string>
<string name="msg_theta_shoot_fail">THETAカメラの撮影に失敗しました。\nWi-Fi接続状態を確認してください。</string>
<string name="msg_transferred">転送済み</string>
<string name="msg_error_device_wifi_off">端末のWi-FiをONにしてください。</string>
<string name="msg_transferring">転送中...</string>
<string name="msg_theta_live_image_fail">THETA端末からライブ画像データ取得に失敗しました。\nWi-Fi接続状態を確認してください。</string>
<string name="msg_theta_set_exposure_fail">露出情報の設定に失敗しました。\nWi-Fi接続状態を確認してください。</string>
<string name="msg_theta_get_exposure_fail">露出情報の取得に失敗しました。\nWi-Fi接続状態を確認してください。</string>
<string name="title_theta_exposure_value">EV:%s</string>
<string name="msg_device_location_off">端末の位置情報機能がONにしてください。</string>
<string name="msg_theta_wifi_disconnect">THETAカメラとWi-Fi接続が切断されましたので、シーン画像選択画面に戻ります。</string>
</resources>
......@@ -362,7 +362,7 @@
<string name="label_entry">등록</string>
<string name="label_base_file">베이스 파일</string>
<string name="select_image">이미지 선택</string>
<string name="error_msg_open_pano_edit">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다(%1$s).</string>
<string name="error_msg_open_pano_edit">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다.</string>
<string name="P001">자료명에 반각가타가나는 사용할 수 없습니다.</string>
<string name="P002">이미 자료가 등록되어 있습니다.</string>
......@@ -583,7 +583,7 @@
<string name="label_entry_1">등록(1)</string>
<string name="label_base_file_1">베이스 파일(1)</string>
<string name="select_image_1">이미지 선택(1)</string>
<string name="error_msg_open_pano_edit_1">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다(%1$s).(1)</string>
<string name="error_msg_open_pano_edit_1">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다.(1)</string>
<string name="P001_1">자료명에 반각가타가나는 사용할 수 없습니다.(1)</string>
<string name="P002_1">이미 자료가 등록되어 있습니다.(1)</string>
......@@ -761,7 +761,7 @@
<string name="label_entry_2">등록(2)</string>
<string name="label_base_file_2">베이스 파일(2)</string>
<string name="select_image_2">이미지 선택(2)</string>
<string name="error_msg_open_pano_edit_2">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다(%1$s).(2)</string>
<string name="error_msg_open_pano_edit_2">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다.(2)</string>
<string name="P001_2">자료명에 반각가타가나는 사용할 수 없습니다.(2)</string>
<string name="P002_2">이미 자료가 등록되어 있습니다.(2)</string>
......@@ -938,7 +938,7 @@
<string name="label_entry_3">등록(3)</string>
<string name="label_base_file_3">베이스 파일(3)</string>
<string name="select_image_3">이미지 선택(3)</string>
<string name="error_msg_open_pano_edit_3">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다(%1$s).(3)</string>
<string name="error_msg_open_pano_edit_3">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다.(3)</string>
<string name="P001_3">자료명에 반각가타가나는 사용할 수 없습니다.(3)</string>
<string name="P002_3">이미 자료가 등록되어 있습니다.(3)</string>
......@@ -1115,7 +1115,7 @@
<string name="label_entry_4">등록(4)</string>
<string name="label_base_file_4">베이스 파일(4)</string>
<string name="select_image_4">이미지 선택(4)</string>
<string name="error_msg_open_pano_edit_4">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다(%1$s).(4)</string>
<string name="error_msg_open_pano_edit_4">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다.(4)</string>
<string name="P001_4">자료명에 반각가타가나는 사용할 수 없습니다.(4)</string>
<string name="P002_4">이미 자료가 등록되어 있습니다.(4)</string>
......@@ -1292,7 +1292,7 @@
<string name="label_entry_5">등록(5)</string>
<string name="label_base_file_5">베이스 파일(5)</string>
<string name="select_image_5">이미지 선택(5)</string>
<string name="error_msg_open_pano_edit_5">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다(%1$s).(5)</string>
<string name="error_msg_open_pano_edit_5">다른 단말에서 자료를 편집중이기때문에 편집할수 없습니다.(5)</string>
<string name="P001_5">자료명에 반각가타가나는 사용할 수 없습니다.(5)</string>
<string name="P002_5">이미 자료가 등록되어 있습니다.(5)</string>
......@@ -1428,4 +1428,40 @@
<string name="msg_confirm_close_edit_page">편집을 종료하시겠습니까?\n(저장되지 않은 변경 사항은 삭제됩니다.)</string>
<string name="msg_error_edit_page_save">파일 저장 중에 예기치 않은 오류가 발생했습니다.\n편집창을 종료합니다.</string>
<string name="msg_error_edit_page_open">편집창을 여는데 실패했습니다.</string>
<!-- ABookCheck 1.2.300 -->
<string name="title_scene_image_select">장면 이미지 선택</string>
<string name="msg_image_select_max_count_over">장면 이미지의 선택 가능한 최대 개수는 %s개입니다.</string>
<string name="msg_image_select_send_comfirm">선택한 장면 이미지를 등록하시겠습니까?</string>
<string name="msg_image_select_send_success">장면 이미지 등록에 성공하였습니다.</string>
<string name="msg_image_select_send_fail_retry">장면 이미지 등록에 실패하였습니다. 다시 등록 처리를 실행 하시겠습니까?</string>
<string name="msg_access_registing">등록중</string>
<string name="title_theta_camera">THETA카메라</string>
<string name="title_theta_camera_shoot">촬영</string>
<string name="title_theta_library">THETA라이브러리</string>
<string name="title_theta_image_preview">THETA 미리보기</string>
<string name="title_theta_connect">카메라 선택</string>
<string name="msg_wifi_connecting">Wi-Fi 접속중...</string>
<string name="msg_fail_connect_theta_wifi">THETA카메라 접속 실패 하였습니다. THETA카메라의 Wi-Fi설정을 확이해 주세요.</string>
<string name="title_theta_wifi_saved">등록된 단말기</string>
<string name="title_theta_wifi_not_saved">등록되지 않은 단말기</string>
<string name="title_theta_image_save">전송</string>
<string name="msg_theta_image_send_confirm">이미지를 전송 하시겠습니까?</string>
<string name="msg_theta_image_delete_confirm">이미지를 삭제 하시겠습니까?</string>
<string name="msg_theta_image_send_success">이미지 전송에 성공하였습니다.</string>
<string name="msg_theta_image_send_fail">이미지 전송에 실패하였습니다.\nWi-Fi접속 상태를 확인해 주세요.</string>
<string name="msg_theta_image_delete_success">이미지 삭제에 성공하였습니다.</string>
<string name="msg_theta_image_delete_fail">이미지 삭제에 실패하였습니다.\nWi-Fi접속 상태를 확인해 주세요.</string>
<string name="msg_theta_image_load_fail">이미지 정보 취득에 실패하였습니다.\nWi-Fi접속 상태를 확인해 주세요.</string>
<string name="msg_deleting">삭제중...</string>
<string name="msg_theta_shoot_fail">THETA카메라 촬영에 실패하였습니다.\nWi-Fi접속 상태를 확인해 주세요.</string>
<string name="msg_transferred">전송 완료</string>
<string name="msg_error_device_wifi_off">단말기의 Wi-Fi를 ON으로 설정해 주세요.</string>
<string name="msg_transferring">전송중...</string>
<string name="msg_theta_live_image_fail">THETA카메라에서 라이브 영상정보 취득에 실패하였습니다.\nWi-Fi접속 상태를 확인해 주세요.</string>
<string name="msg_theta_set_exposure_fail">노출 정보 설정에 실패하였습니다.\nWi-Fi접속 상태를 확인해 주세요.</string>
<string name="msg_theta_get_exposure_fail">노출 정보 취득에 실패하였습니다.\nWi-Fi접속 상태를 확인해 주세요.</string>
<string name="title_theta_exposure_value">EV:%s</string>
<string name="msg_device_location_off">단말기의 위치정보 기능을 ON으로 설정해 주세요.</string>
<string name="msg_theta_wifi_disconnect">THETA 카메라 Wi-Fi 접속이 끊겼습니다. 장면 이미지 선택 화면으로 돌아갑니다.</string>
</resources>
\ No newline at end of file
......@@ -89,4 +89,10 @@
<color name="operation_bg">#FFFFFF</color>
<color name="bottom_toolbar">#F2F2F2</color>
<color name="dialog_text_color">#000000</color>
<color name="theta_wifi_connect_dialog_background">#F7F7F7</color>
<color name="theta_wifi_connect_dialog_title_color">#989898</color>
</resources>
\ No newline at end of file
......@@ -366,7 +366,7 @@
<string name="label_entry">Registration</string>
<string name="label_base_file">Base file</string>
<string name="select_image">Image selection</string>
<string name="error_msg_open_pano_edit">The content can not be edited (%1$s) because the content is being edited on another terminal.</string> d
<string name="error_msg_open_pano_edit">The content can not be edited because the content is being edited on another terminal.</string> d
<string name="P001">Hankaku katakana can not be used for content name.</string>
<string name="P002">Content has already been registered.</string>
......@@ -586,7 +586,7 @@
<string name="label_entry_1">Registration(1)</string>
<string name="label_base_file_1">Base file(1)</string>
<string name="select_image_1">Image selection(1)</string>
<string name="error_msg_open_pano_edit_1">The content can not be edited (%1$s) because the content is being edited on another terminal.(1)</string>
<string name="error_msg_open_pano_edit_1">The content can not be edited because the content is being edited on another terminal.(1)</string>
<string name="P001_1">Hankaku katakana can not be used for content name.(1)</string>
<string name="P002_1">Content has already been registered.(1)</string>
......@@ -762,7 +762,7 @@
<string name="label_entry_2">Registration(2)</string>
<string name="label_base_file_2">Base file(2)</string>
<string name="select_image_2">Image selection(2)</string>
<string name="error_msg_open_pano_edit_2">The content can not be edited (%1$s) because the content is being edited on another terminal.(2)</string>
<string name="error_msg_open_pano_edit_2">The content can not be edited because the content is being edited on another terminal.(2)</string>
<string name="P001_2">Hankaku katakana can not be used for content name.(2)</string>
<string name="P002_2">Content has already been registered.(2)</string>
......@@ -938,7 +938,7 @@
<string name="label_entry_3">Registration(3)</string>
<string name="label_base_file_3">Base file(3)</string>
<string name="select_image_3">Image selection(3)</string>
<string name="error_msg_open_pano_edit_3">The content can not be edited (%1$s) because the content is being edited on another terminal.(3)</string>
<string name="error_msg_open_pano_edit_3">The content can not be edited because the content is being edited on another terminal.(3)</string>
<string name="P001_3">Hankaku katakana can not be used for content name.(3)</string>
<string name="P002_3">Content has already been registered.(3)</string>
......@@ -1114,7 +1114,7 @@
<string name="label_entry_4">Registration(4)</string>
<string name="label_base_file_4">Base file(4)</string>
<string name="select_image_4">Image selection(4)</string>
<string name="error_msg_open_pano_edit_4">The content can not be edited (%1$s) because the content is being edited on another terminal.(4)</string>
<string name="error_msg_open_pano_edit_4">The content can not be edited because the content is being edited on another terminal.(4)</string>
<string name="P001_4">Hankaku katakana can not be used for content name.(4)</string>
<string name="P002_4">Content has already been registered.(4)</string>
......@@ -1290,7 +1290,7 @@
<string name="label_entry_5">Registration(5)</string>
<string name="label_base_file_5">Base file(5)</string>
<string name="select_image_5">Image selection(5)</string>
<string name="error_msg_open_pano_edit_5">The content can not be edited (%1$s) because the content is being edited on another terminal.(5)</string>
<string name="error_msg_open_pano_edit_5">The content can not be edited because the content is being edited on another terminal.(5)</string>
<string name="P001_5">Hankaku katakana can not be used for content name.(5)</string>
<string name="P002_5">Content has already been registered.(5)</string>
......@@ -1427,4 +1427,40 @@
<string name="msg_error_edit_page_save">An unexpected error has occurred while saving the image.\nClosing the editing Page.</string>
<string name="msg_error_edit_page_open">Failed to open the edit tool.</string>
</resources>
\ No newline at end of file
<!-- ABookCheck 1.2.300 -->
<string name="title_scene_image_select">Select scene image</string>
<string name="msg_image_select_max_count_over">The maximum number of scene images that can be selected is %s.</string>
<string name="msg_image_select_send_comfirm">Register the selected scene image?</string>
<string name="msg_image_select_send_success">You have successfully registered a scene image.</string>
<string name="msg_image_select_send_fail_retry">Registration of the scene image failed. Do you want to register again?</string>
<string name="msg_access_registing">Registring</string>
<string name="title_theta_camera">THETA Camera</string>
<string name="title_theta_camera_shoot">Shoot</string>
<string name="title_theta_library">THETA Library</string>
<string name="title_theta_image_preview">THETA Preview</string>
<string name="title_theta_connect">Camera Select</string>
<string name="msg_wifi_connecting">Wi-Fi connecting...</string>
<string name="msg_fail_connect_theta_wifi">THETA camera connection failed. Check the Wi-Fi settings of THETA camera.</string>
<string name="title_theta_wifi_saved">Registered device</string>
<string name="title_theta_wifi_not_saved">Unregistered device</string>
<string name="title_theta_image_save">transfer</string>
<string name="msg_theta_image_send_confirm">Would you like to transfer this image?</string>
<string name="msg_theta_image_delete_confirm">Are you sure you want to delete this image?</string>
<string name="msg_theta_image_send_success">Image transfer successful.</string>
<string name="msg_theta_image_send_fail">Image transfer failed.\nPlease check the Wi-Fi connection status.</string>
<string name="msg_theta_image_delete_success">Image delete successful.</string>
<string name="msg_theta_image_delete_fail">Image delete failed.\nPlease check the Wi-Fi connection status.</string>
<string name="msg_theta_image_load_fail">Failed to load image.\nPlease check the Wi-Fi connection status.</string>
<string name="msg_deleting">Deleting...</string>
<string name="msg_theta_shoot_fail">The THETA camera failed to shoot.\nPlease check the Wi-Fi connection status.</string>
<string name="msg_transferred">Transferred</string>
<string name="msg_error_device_wifi_off">Set the Wi-Fi of the device to ON.</string>
<string name="msg_transferring">transferring...</string>
<string name="msg_theta_live_image_fail">Failed to acquire live video information from THETA camera.\nPlease check the Wi-Fi connection status.</string>
<string name="msg_theta_set_exposure_fail">Failed to set exposure value.\nPlease check the Wi-Fi connection status.</string>
<string name="msg_theta_get_exposure_fail">Failed to acquire exposure value.\nPlease check the Wi-Fi connection status.</string>
<string name="title_theta_exposure_value">EV:%s</string>
<string name="msg_device_location_off">Set the location information function of the Device to ON.</string>
<string name="msg_theta_wifi_disconnect">THETA camera Wi-Fi connection has been lost. return to Select scene image screen.</string>
</resources>
\ No newline at end of file
......@@ -8,6 +8,7 @@
<uses-sdk tools:overrideLibrary="org.xwalk.core"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
......@@ -16,4 +17,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Wifi使用権限 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="#D3D3D3"/>
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<scale
android:scaleWidth="100%" >
<shape android:shape="rectangle">
<solid android:color="#D3D3D3"/>
</shape>
</scale>
</item>
<item android:id="@android:id/progress">
<scale
android:scaleWidth="100%" >
<shape android:shape="rectangle">
<solid android:color="#D3D3D3"/>
</shape>
</scale>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="-6dp"
android:left="-3dp"
android:top="-6dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
<stroke
android:width="2dp"
android:color="#D3D3D3" />
</shape>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/device_connect_toolbar"
style="@style/OperationSearchToolBar"
android:layout_width="match_parent"
android:layout_height="50dp">
<Button
android:id="@+id/regist"
android:layout_width="87dp"
android:layout_height="45dp"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/label_entry" />
<Button
android:id="@+id/theta_camera"
android:layout_width="87dp"
android:layout_height="45dp"
android:layout_toRightOf="@id/regist"
android:layout_centerVertical="true"
android:layout_alignParentBottom="true"
android:text="THETA" />
<TextView
android:id="@+id/device_image_list_title"
style="@style/DialogToolBarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/title_scene_image_select"
android:textColor="@color/edt_text"
android:textSize="@dimen/opeartion_title_text_size" />
<Button
android:id="@+id/close"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_operation_close"
android:contentDescription="@string/cont_desc" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/alert_background"
android:orientation="vertical">
<GridView
android:id="@+id/gallery_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawSelectorOnTop="false"
android:horizontalSpacing="2dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="2dp" />
</LinearLayout>
<!--android:listSelector="?android:attr/selectableItemBackground" -->
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/device_connect_toolbar"
style="@style/OperationSearchToolBar"
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:id="@+id/theta_camera_title"
style="@style/DialogToolBarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/title_theta_camera"
android:textColor="@color/edt_text"
android:textSize="@dimen/opeartion_title_text_size" />
<Button
android:id="@+id/btn_close"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_operation_close"
android:contentDescription="@string/cont_desc" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.theta.view.MJpegView
android:id="@+id/live_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_alignParentBottom="true"
android:alpha="0.3"
android:background="@android:color/black">
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_alignParentBottom="true"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_exposure"
android:layout_width="55dp"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="EV:1.3"
android:textColor="@android:color/white"
android:textSize="18sp" />
<SeekBar
android:id="@+id/sb_exposure_old"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:background="@android:color/transparent"
android:max="12"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:progress="2"
android:progressDrawable="@drawable/theta_exposure_progress_drawable"
android:thumb="@android:drawable/radiobutton_off_background"
android:visibility="gone"/>
<SeekBar
android:id="@+id/sb_exposure"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:background="@android:color/transparent"
android:max="12"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:progress="2"
android:progressDrawable="@drawable/theta_exposure_progress_drawable"
android:thumb="@drawable/seek_handler"
android:tickMark="@drawable/theta_exposure_tickmark" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_theta_camera_image_list"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/btn_theta_list" />
<Button
android:id="@+id/btn_theta_camera_shoot"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerInParent="true"
android:background="@drawable/btn_theta_shoot" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/device_connect_toolbar"
style="@style/OperationSearchToolBar"
android:layout_width="match_parent"
android:layout_height="50dp">
<Button
android:id="@+id/btn_back"
android:layout_width="87dp"
android:layout_height="45dp"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/back" />
<TextView
android:id="@+id/theta_library_title"
style="@style/DialogToolBarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/title_theta_library"
android:textColor="@color/edt_text"
android:textSize="@dimen/opeartion_title_text_size" />
</RelativeLayout>
<ListView
android:id="@+id/lv_theta_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:divider="@android:color/darker_gray"
android:dividerHeight="1px"
/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/device_connect_toolbar"
style="@style/OperationSearchToolBar"
android:layout_width="match_parent"
android:layout_height="50dp">
<Button
android:id="@+id/btn_back"
android:layout_width="87dp"
android:layout_height="45dp"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/back" />
<TextView
android:id="@+id/theta_imagePreview_title"
style="@style/DialogToolBarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/title_theta_image_preview"
android:textColor="@color/edt_text"
android:textSize="@dimen/opeartion_title_text_size" />
<Button
android:id="@+id/btn_theta_image_save"
android:layout_width="87dp"
android:layout_height="45dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/title_theta_image_save" />
</RelativeLayout>
<com.theta.glview.GLPhotoView
android:id="@+id/photo_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@android:color/darker_gray"
android:dividerHeight="1px" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff">
<ImageView
android:id="@+id/iv_thumbnail"
android:layout_width="match_parent"
android:layout_height="150dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
<ImageView
android:id="@+id/iv_thumbnail_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/check_mark" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_item"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="5dp"
android:gravity="center_vertical"
android:text="TextView" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/object_list_row"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:descendantFocusability="blocksDescendants">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false">
<ImageView
android:id="@+id/object_thumbnail"
android:layout_width="120dp"
android:layout_height="80dp"
android:scaleType="fitXY"
android:layout_centerVertical="true" />
<LinearLayout
android:id="@+id/ll_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/object_thumbnail"
android:orientation="vertical">
<TextView
android:id="@+id/tv_file_name"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/tv_create_date"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/tv_transferred_status"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="@string/msg_transferred"
android:textColor="@android:color/holo_red_dark" />
</LinearLayout>
<Button
android:id="@+id/btn_theta_image_save"
android:layout_width="85dp"
android:layout_height="45dp"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/btn_theta_image_delete"
android:text="@string/title_theta_image_save" />
<Button
android:id="@+id/btn_theta_image_delete"
android:layout_width="85dp"
android:layout_height="45dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:text="@string/delete" />
</RelativeLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/theta_wifi_connect_dialog_background"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/device_connect_toolbar"
style="@style/OperationSearchToolBar"
android:layout_width="match_parent"
android:layout_height="50dp">
<Button
android:id="@+id/btn_theta_update"
android:layout_width="87dp"
android:layout_height="45dp"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="@string/content_update"
android:textSize="@dimen/dialog_button_text_size"/>
<TextView
android:id="@+id/theta_camera_connect"
style="@style/DialogToolBarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/title_theta_connect"
android:textColor="@android:color/black"
android:textSize="@dimen/dialog_title_text_size"/>
<Button
android:id="@+id/btn_close"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_operation_close"
android:contentDescription="@string/cont_desc"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title_theta_wifi_saved"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="@string/title_theta_wifi_saved"
android:textColor="@color/theta_wifi_connect_dialog_title_color"
android:textSize="@dimen/dialog_text_size" />
<ListView
android:id="@+id/lv_theta_wifi_saved"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@android:color/white"
android:divider="@null"
android:dividerHeight="0dp"
android:minHeight="150dp" />
<TextView
android:id="@+id/tv_title_theta_wifi_not_saved"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/title_theta_wifi_not_saved"
android:textColor="@color/theta_wifi_connect_dialog_title_color"
android:textSize="@dimen/dialog_text_size" />
<ListView
android:id="@+id/lv_theta_wifi_not_saved"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@android:color/white"
android:divider="@null"
android:dividerHeight="0dp"
android:minHeight="150dp" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="opeartion_title_text_size" />
<dimen name="dialog_title_text_size">18dp</dimen>
<dimen name="dialog_text_size">15dp</dimen>
<dimen name="dialog_button_text_size">13dp</dimen>
</resources>
\ No newline at end of file
/*
* 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.imagepicker;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* A simple subclass of {@link ImageResizer} that fetches and resizes images fetched from a URL.
*/
public class ImageFetcher extends ImageResizer {
private static final String TAG = "ImageFetcher";
private static final int HTTP_CACHE_SIZE = 10 * 1024 * 1024; // 10MB
private static final String HTTP_CACHE_DIR = "http";
private static final int IO_BUFFER_SIZE = 8 * 1024;
private DiskLruCache mHttpDiskCache;
private File mHttpCacheDir;
private boolean mHttpDiskCacheStarting = true;
private final Object mHttpDiskCacheLock = new Object();
private static final int DISK_CACHE_INDEX = 0;
/**
* Initialize providing a target image width and height for the processing images.
*
* @param context
* @param imageWidth
* @param imageHeight
*/
public ImageFetcher(Context context, int imageWidth, int imageHeight) {
super(context, imageWidth, imageHeight);
init(context);
}
/**
* Initialize providing a single target image size (used for both width and height);
*
* @param context
* @param imageSize
*/
public ImageFetcher(Context context, int imageSize) {
super(context, imageSize);
init(context);
}
private void init(Context context) {
checkConnection(context);
mHttpCacheDir = ImageCache.getDiskCacheDir(context, HTTP_CACHE_DIR);
}
@Override
protected void initDiskCacheInternal() {
super.initDiskCacheInternal();
initHttpDiskCache();
}
private void initHttpDiskCache() {
if (!mHttpCacheDir.exists()) {
mHttpCacheDir.mkdirs();
}
synchronized (mHttpDiskCacheLock) {
if (ImageCache.getUsableSpace(mHttpCacheDir) > HTTP_CACHE_SIZE) {
try {
mHttpDiskCache = DiskLruCache.open(mHttpCacheDir, 1, 1, HTTP_CACHE_SIZE);
} catch (IOException e) {
mHttpDiskCache = null;
}
}
mHttpDiskCacheStarting = false;
mHttpDiskCacheLock.notifyAll();
}
}
@Override
protected void clearCacheInternal() {
super.clearCacheInternal();
synchronized (mHttpDiskCacheLock) {
if (mHttpDiskCache != null && !mHttpDiskCache.isClosed()) {
try {
mHttpDiskCache.delete();
Log.d(TAG, "HTTP cache cleared");
} catch (IOException e) {
Log.e(TAG, "clearCacheInternal - " + e);
}
mHttpDiskCache = null;
mHttpDiskCacheStarting = true;
initHttpDiskCache();
}
}
}
@Override
protected void flushCacheInternal() {
super.flushCacheInternal();
synchronized (mHttpDiskCacheLock) {
if (mHttpDiskCache != null) {
try {
mHttpDiskCache.flush();
} catch (IOException e) {
Log.e(TAG, "flush - " + e);
}
}
}
}
@Override
protected void closeCacheInternal() {
super.closeCacheInternal();
synchronized (mHttpDiskCacheLock) {
if (mHttpDiskCache != null) {
try {
if (!mHttpDiskCache.isClosed()) {
mHttpDiskCache.close();
mHttpDiskCache = null;
}
} catch (IOException e) {
Log.e(TAG, "closeCacheInternal - " + e);
}
}
}
}
/**
* Simple network connection check.
*
* @param context
*/
private void checkConnection(Context context) {
final ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if (networkInfo == null || !networkInfo.isConnectedOrConnecting()) {
Log.e(TAG, "checkConnection - no connection found");
}
}
/**
* The main process method, which will be called by the ImageWorker in the AsyncTask background
* thread.
*
* @param data The data to load the bitmap, in this case, a regular http URL
* @return The downloaded and resized bitmap
*/
private Bitmap processBitmap(String data) {
final String key = ImageCache.hashKeyForDisk(data);
FileDescriptor fileDescriptor = null;
FileInputStream fileInputStream = null;
DiskLruCache.Snapshot snapshot;
synchronized (mHttpDiskCacheLock) {
// Wait for disk cache to initialize
while (mHttpDiskCacheStarting) {
try {
mHttpDiskCacheLock.wait();
} catch (InterruptedException e) {}
}
if (mHttpDiskCache != null) {
try {
snapshot = mHttpDiskCache.get(key);
if (snapshot == null) {
DiskLruCache.Editor editor = mHttpDiskCache.edit(key);
if (editor != null) {
if (downloadUrlToStream(data,
editor.newOutputStream(DISK_CACHE_INDEX))) {
editor.commit();
} else {
editor.abort();
}
}
snapshot = mHttpDiskCache.get(key);
}
if (snapshot != null) {
fileInputStream =
(FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX);
fileDescriptor = fileInputStream.getFD();
}
} catch (IOException e) {
Log.e(TAG, "processBitmap - " + e);
} catch (IllegalStateException e) {
Log.e(TAG, "processBitmap - " + e);
} finally {
if (fileDescriptor == null && fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {}
}
}
}
}
Bitmap bitmap = null;
if (fileDescriptor != null) {
bitmap = decodeSampledBitmapFromDescriptor(fileDescriptor, mImageWidth,
mImageHeight, getImageCache());
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {}
}
return bitmap;
}
@Override
protected Bitmap processBitmap(Object data) {
return processBitmap(String.valueOf(data));
}
/**
* Download a bitmap from a URL and write the content to an output stream.
*
* @param urlString The URL to fetch
* @return true if successful, false otherwise
*/
public boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
disableConnectionReuseIfNecessary();
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE);
out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (final IOException e) {
Log.e(TAG, "Error in downloadBitmap - " + e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (final IOException e) {}
}
return false;
}
/**
* Workaround for bug pre-Froyo, see here for more info:
* http://android-developers.blogspot.com/2011/09/androids-http-clients.html
*/
public static void disableConnectionReuseIfNecessary() {
// HTTP connection reuse which was buggy pre-froyo
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}
}
package com.imagepicker;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
/**
* Created by Gil on 07/06/2014.
*/
public class ImageInternalFetcher extends ImageResizer {
Context mContext;
public ImageInternalFetcher(Context context, int imageWidth, int imageHeight) {
super(context, imageWidth, imageHeight);
init(context);
}
public ImageInternalFetcher(Context context, int imageSize) {
super(context, imageSize);
init(context);
}
private void init(Context context){
mContext = context;
}
protected Bitmap processBitmap(Uri uri){
return decodeSampledBitmapFromFile(uri.getPath(), mImageWidth, mImageHeight, getImageCache());
}
@Override
protected Bitmap processBitmap(Object data) {
return processBitmap((Uri)data);
}
}
/*
* Copyright (C) 2013 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.imagepicker;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
/**
* A BitmapDrawable that keeps track of whether it is being displayed or cached.
* When the drawable is no longer being displayed or cached,
* {@link android.graphics.Bitmap#recycle() recycle()} will be called on this drawable's bitmap.
*/
public class RecyclingBitmapDrawable extends BitmapDrawable {
static final String TAG = "CountingBitmapDrawable";
private int mCacheRefCount = 0;
private int mDisplayRefCount = 0;
private boolean mHasBeenDisplayed;
public RecyclingBitmapDrawable(Resources res, Bitmap bitmap) {
super(res, bitmap);
}
/**
* Notify the drawable that the displayed state has changed. Internally a
* count is kept so that the drawable knows when it is no longer being
* displayed.
*
* @param isDisplayed - Whether the drawable is being displayed or not
*/
public void setIsDisplayed(boolean isDisplayed) {
//BEGIN_INCLUDE(set_is_displayed)
synchronized (this) {
if (isDisplayed) {
mDisplayRefCount++;
mHasBeenDisplayed = true;
} else {
mDisplayRefCount--;
}
}
// Check to see if recycle() can be called
checkState();
//END_INCLUDE(set_is_displayed)
}
/**
* Notify the drawable that the cache state has changed. Internally a count
* is kept so that the drawable knows when it is no longer being cached.
*
* @param isCached - Whether the drawable is being cached or not
*/
public void setIsCached(boolean isCached) {
//BEGIN_INCLUDE(set_is_cached)
synchronized (this) {
if (isCached) {
mCacheRefCount++;
} else {
mCacheRefCount--;
}
}
// Check to see if recycle() can be called
checkState();
//END_INCLUDE(set_is_cached)
}
private synchronized void checkState() {
//BEGIN_INCLUDE(check_state)
// If the drawable cache and display ref counts = 0, and this drawable
// has been displayed, then recycle
if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
&& hasValidBitmap()) {
getBitmap().recycle();
}
//END_INCLUDE(check_state)
}
private synchronized boolean hasValidBitmap() {
Bitmap bitmap = getBitmap();
return bitmap != null && !bitmap.isRecycled();
}
}
/*
* 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.imagepicker;
import android.os.Build;
import android.os.Build.VERSION_CODES;
/**
* Class containing some static utility methods.
*/
public class Utils {
private Utils() {};
public static boolean hasFroyo() {
// Can use static final constants like FROYO, declared in later versions
// of the OS since they are inlined at compile time. This is guaranteed behavior.
return Build.VERSION.SDK_INT >= VERSION_CODES.FROYO;
}
public static boolean hasGingerbread() {
return Build.VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD;
}
public static boolean hasHoneycomb() {
return Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB;
}
public static boolean hasHoneycombMR1() {
return Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1;
}
public static boolean hasJellyBean() {
return Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN;
}
public static boolean hasKitKat() {
return Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT;
}
}
package com.theta.glview;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.Scroller;
import com.theta.model.Constants;
import com.theta.model.Photo;
import com.theta.model.RotateInertia;
/**
* View class for photo display
*/
public class GLPhotoView extends GLSurfaceView {
private static final int ANIMATION_INTERVAL = 10;
private GLRenderer mRenderer = null;
private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
private Scroller mScroller = null;
private float mPrevX, mPrevY;
private RotateInertia mRotateInertia = RotateInertia.INERTIA_0;
/**
* Constructor
* @param context Context
*/
public GLPhotoView(Context context) {
this(context, null);
}
/**
* Constructor
* @param context Context
* @param attrs Argument for resource
*/
public GLPhotoView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context);
}
/**
* onTouchEvent Event listener
* @param event Event object
* @return Process continuation judgment value
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean ret = false;
mScaleGestureDetector.onTouchEvent(event);
if (!mScaleGestureDetector.isInProgress()) {
ret = mGestureDetector.onTouchEvent(event);
if (!ret) {
super.onTouchEvent(event);
}
}
return ret;
}
private void initialize(Context context) {
setEGLContextClientVersion(2);
mRenderer = new GLRenderer();
setRenderer(mRenderer);
setLongClickable(true);
mGestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() {
private final int SWIPE_MAX_OF_PATH_X = 100;
private final int SWIPE_MAX_OF_PATH_Y = 100;
final Handler handler = new Handler();
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
return;
}
@Override
public void onLongPress(MotionEvent e) {
return;
}
@Override
public boolean onDown(MotionEvent e) {
if (null != mScroller && !mScroller.isFinished()) {
mScroller.abortAnimation();
handler.removeCallbacksAndMessages(null);
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
boolean ret = false;
if (null != mScroller && !mScroller.isFinished()) {
mScroller.abortAnimation();
}
if ((Math.abs(distanceX) > SWIPE_MAX_OF_PATH_X ) || (Math.abs(distanceY) > SWIPE_MAX_OF_PATH_Y )) {
ret = false;
} else {
float diffX = distanceX / Constants.ON_SCROLL_DIVIDER_X;
float diffY = distanceY / Constants.ON_SCROLL_DIVIDER_Y;
if (Math.abs(diffX) < Constants.THRESHOLD_SCROLL_X) {
diffX = 0.0f;
}
if (Math.abs(diffY) < Constants.THRESHOLD_SCROLL_Y) {
diffY = 0.0f;
}
if (null != mRenderer) {
mRenderer.rotate(diffX, -diffY);
}
ret = true;
}
return ret;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mScroller.fling((int)e2.getX(), (int)e2.getY(), (int)velocityX, (int)velocityY, 0, getWidth(), 0, getHeight());
mPrevX = e2.getX();
mPrevY = e2.getY();
handler.post(new Runnable() {
@Override
public void run() {
if (mRotateInertia == RotateInertia.INERTIA_0) {
// do nothing
}
else {
mScroller.computeScrollOffset();
float diffX = mScroller.getCurrX() - mPrevX;
float diffY = mScroller.getCurrY() - mPrevY;
mPrevX = mScroller.getCurrX();
mPrevY = mScroller.getCurrY();
if (mRotateInertia == RotateInertia.INERTIA_50) {
diffX = diffX / Constants.ON_FLING_DIVIDER_X_FOR_INERTIA_50;
diffY = diffY / Constants.ON_FLING_DIVIDER_Y_FOR_INERTIA_50;
}
else {
diffX = diffX / Constants.ON_FLING_DIVIDER_X_FOR_INERTIA_100;
diffY = diffY / Constants.ON_FLING_DIVIDER_Y_FOR_INERTIA_100;
}
mRenderer.rotate((float) -diffX, (float) diffY);
if (!mScroller.isFinished()) {
handler.postDelayed(this, ANIMATION_INTERVAL);
}
}
}
});
return true;
}
});
mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
if (null != mRenderer) {
mRenderer.scale(scale);
}
return true;
}
});
mScroller = new Scroller(context);
return;
}
/**
* Texture setting method
* @param thumbnail Photo object for texture
*/
public void setTexture(Photo thumbnail) {
mRenderer.setTexture(thumbnail);
return;
}
/**
* Inertia setting method
* @param mRotateInertia Setting inertia value
*/
public void setmRotateInertia(RotateInertia mRotateInertia) {
this.mRotateInertia = mRotateInertia;
return;
}
}
\ No newline at end of file
package com.theta.glview.model;
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
/**
* UV sphere model class
*/
public class UVSphere {
private final int COORDS_PER_VERTEX = 3;
private final int TEXTURE_COORDS_PER_VERTEX = 2;
private int mStrips;
private int mStripePointsNum;
private ArrayList<FloatBuffer> mVertices;
private ArrayList<FloatBuffer> mTextureCoords;
private final int vertexStride = COORDS_PER_VERTEX * 4;
private final int textureStride = TEXTURE_COORDS_PER_VERTEX * 4;
private UVSphere() {
mVertices = new ArrayList<FloatBuffer>();
mTextureCoords = new ArrayList<FloatBuffer>();
}
/**
* Constructor
* Sphere is displayed according to the number of partitions.
* The longitude is created from the number of partitions which is half the number of
* latitude lines 1 and the number of polygons which is double the number of
* partitions set in the radius specified as the origin coordinates.
* @param radius Radius
* @param divide Number of partitions (must be an even number)
* @param eastSide true is east side of sphere, otherwise is west side
*/
public UVSphere(float radius, int divide, boolean eastSide) {
this();
if (radius <= 0 || divide <= 0 || 0 != (divide % 2)) {
throw new IllegalArgumentException();
}
mStrips = divide/2;
mStripePointsNum = (divide+1)*2;
makeSphereVertices(radius, divide, eastSide);
}
/**
* Sphere drawing method
* @param mPositionHandle Handler value tied to gl_Position in vertex shader
* @param mUVHandle Handler value tied to the UV coordinates provided to the fragment shader via the varyig variable
*/
public void draw(int mPositionHandle, int mUVHandle) {
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glEnableVertexAttribArray(mUVHandle);
for (int i = 0; i < this.mStrips; i++) {
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, mVertices.get(i));
GLES20.glVertexAttribPointer(mUVHandle, TEXTURE_COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, textureStride, mTextureCoords.get(i));
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mStripePointsNum);
}
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mUVHandle);
return;
}
private void makeSphereVertices(float radius, int divide, boolean eastSide) {
float altitude = 0.0f;
float altitudeDelta = 0.0f;
float azimuth = 0.0f;
float ex = 0.0f;
float ey = 0.0f;
float ez = 0.0f;
Double startPoint;
if (eastSide) {
startPoint = 0.0d;
} else {
startPoint = Math.PI;
}
for(int i = 0; i < divide/2; ++i)
{
altitude = (float) (Math.PI/2.0 - i * (Math.PI*2) / divide);
altitudeDelta = (float) (Math.PI/2.0 - (i + 1) * (Math.PI*2) / divide);
float[] vertices = new float[divide*6+6];
float[] texCoords = new float[divide*4+4];
for(int j = 0; j <= divide/2; ++j)
{
azimuth = (float) (startPoint - (j * (Math.PI*2) / divide));
// first point
ex = (float) (Math.cos(altitudeDelta) * Math.cos(azimuth));
ey = (float) Math.sin(altitudeDelta);
ez = (float) (Math.cos(altitudeDelta) * Math.sin(azimuth));
vertices[6*j+0] = radius * ex;
vertices[6*j+1] = radius * ey;
vertices[6*j+2] = radius * ez;
texCoords[4*j+0] = 1.0f-(2*j/(float)divide);
texCoords[4*j+1] = 2*(i+1)/(float)divide;
// second point
ex = (float) (Math.cos(altitude) * Math.cos(azimuth));
ey = (float) Math.sin(altitude);
ez = (float) (Math.cos(altitude) * Math.sin(azimuth));
vertices[6*j+3] = radius * ex;
vertices[6*j+4] = radius * ey;
vertices[6*j+5] = radius * ez;
texCoords[4*j+2] = 1.0f-(2*j/(float)divide);
texCoords[4*j+3] = 2*i/(float)divide;
}
mVertices.add(makeFloatBufferFromArray(vertices));
mTextureCoords.add(makeFloatBufferFromArray(texCoords));
}
return;
}
private FloatBuffer makeFloatBufferFromArray(float[] array) {
FloatBuffer fb = ByteBuffer.allocateDirect(array.length*Float.SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
fb.put(array);
fb.position(0);
return fb;
}
}
package com.theta.model;
/**
* Constant used by the program
*/
public interface Constants {
/** Radius of sphere for photo */
static final int TEXTURE_SHELL_RADIUS = 2;
/** Number of sphere polygon partitions for photo, which must be an even number */
static final int SHELL_DIVIDES = 40;
/** Maximum value that can be specified as the camera FOV variable */
static final int CAMERA_FOV_DEGREE_MAX = 100;
/** Minimum value that can be specified as the camera FOV variable */
static final int CAMERA_FOV_DEGREE_MIN = 30;
/** Pitch width of zoom in process */
static final float SCALE_RATIO_TICK_EXPANSION = 1.05f;
/** Pitch width of zoom out process */
static final float SCALE_RATIO_TICK_REDUCTION = 0.95f;
/** Rotation threshold for scroll (X axis direction) */
static final double THRESHOLD_SCROLL_X = 0.02;
/** Rotation threshold for scroll (Y axis direction) */
static final double THRESHOLD_SCROLL_Y = 0.02;
/** Rotation amount derivative parameter for scroll (X axis direction) */
static final float ON_SCROLL_DIVIDER_X = 400.0f;
/** Rotation amount derivative parameter for scroll (Y axis direction) */
static final float ON_SCROLL_DIVIDER_Y = 400.0f;
/** Movement amount derivative parameter when inertia setting is small (X axis direction) */
static final float ON_FLING_DIVIDER_X_FOR_INERTIA_50 = 650.0f;
/** Movement amount derivative parameter when inertia setting is small (Y axis direction) */
static final float ON_FLING_DIVIDER_Y_FOR_INERTIA_50 = (650.0f*3.0f);
/** Movement amount derivative parameter when inertia setting is large (X axis direction) */
static final float ON_FLING_DIVIDER_X_FOR_INERTIA_100 = 65.0f;
/** Movement amount derivative parameter when inertia setting is large (Y axis direction) */
static final float ON_FLING_DIVIDER_Y_FOR_INERTIA_100 = (65.0f*10.0f);
}
\ No newline at end of file
package com.theta.model;
/**
* Image size type
*/
public enum ImageSize {
/** 2048x1024 */
IMAGE_SIZE_2048x1024,
/** 5376x2688 */
IMAGE_SIZE_5376x2688
}
package com.theta.model;
import android.graphics.Bitmap;
/**
* Photo object storage class
*/
public class Photo {
private Double mOrientationAngle;
private Double mElevationAngle;
private Double mHorizontalAngle;
private Bitmap mPhoto;
private Photo() {
}
/**
* Constructor
* @param photo Photo object
*/
public Photo(Bitmap photo) {
this(photo, null, null, null);
}
/**
* Constructor
* @param photo Photo object
* @param orientationAngle Orientation angle
* @param elevationAngle Elevation angle
* @param horizontalAngle Horizontal angle
*/
public Photo(Bitmap photo, Double orientationAngle, Double elevationAngle, Double horizontalAngle) {
this();
mOrientationAngle = orientationAngle;
mElevationAngle = elevationAngle;
mHorizontalAngle = horizontalAngle;
mPhoto = photo;
}
/**
* Acquires the orientation angle
* @return Orientation angle
*/
public Double getOrientationAngle() {
return mOrientationAngle;
}
/**
* Acquires the elevation angle
* @return Elevation angle
*/
public Double getElevetionAngle() {
return mElevationAngle;
}
/**
* Acquires the horizontal angle
* @return Horizontal angle
*/
public Double getHorizontalAngle() {
return mHorizontalAngle;
}
/**
* Acquires the photo object
* @return Photo object
*/
public Bitmap getPhoto() {
return mPhoto;
}
/**
* Updates the photo object
* @param drawable Photo object
*/
public void updatePhoto(Bitmap drawable) {
mPhoto = drawable;
}
}
\ No newline at end of file
package com.theta.model;
/**
* Indicates the rotation inertia
*/
public enum RotateInertia {
/** none */
INERTIA_0,
/** weak */
INERTIA_50,
/** strong */
INERTIA_100,;
}
\ No newline at end of file
package com.theta.network;
/**
* HTTP communication download listener class
*/
public interface HttpDownloadListener {
/**
* Total byte count
*/
void onTotalSize(long totalSize);
/**
* Received byte count
*/
void onDataReceived(int size);
}
package com.theta.network;
/**
* HTTP communication event listener class
*/
public interface HttpEventListener {
/**
* Notifies you of the device status check results
* @param newStatus true:Update available, false;No update available
*/
void onCheckStatus(boolean newStatus);
/**
* Notifies you when the file is saved
* @param latestCapturedFileId ID of saved file
*/
void onObjectChanged(String latestCapturedFileId);
/**
* Notify on completion of event
*/
void onCompleted();
/**
* Notify in the event of an error
*/
void onError(String errorMessage);
}
package com.theta.network;
/**
* Image data class
*/
public class ImageData {
private byte[] mRawData;
private Double pitch = 0.0d;
private Double roll = 0.0d;
private Double yaw = 0.0d;
/**
* Acquire raw data of image
* @return Raw data of image
*/
public byte[] getRawData() {
return mRawData;
}
/**
* Set raw data of image
* @param rawData Raw data of image
*/
public void setRawData(byte[] rawData) {
mRawData = rawData;
}
/**
* Acquire pitch angle
* @return Pitch angle
*/
public Double getPitch() {
return pitch;
}
/**
* Set pitch angle
* @param pitch Pitch angle (value must be between -90 and 90)
*/
public void setPitch(Double pitch) {
this.pitch = pitch;
}
/**
* Acquire roll angle
* @return Roll angle
*/
public Double getRoll() {
return roll;
}
/**
* Set roll angle
* @param roll Roll angle (value must be between -180 and 180)
*/
public void setRoll(Double roll) {
this.roll = roll;
}
/**
* Acquire yaw angle
* @return Yaw angle
*/
public Double getYaw() {
return yaw;
}
/**
* Set yaw angle
* @param yaw Yaw angle (value must be between 0 and 360)
*/
public void setYaw(Double yaw) {
this.yaw = yaw;
}
}
package com.theta.network;
import java.text.SimpleDateFormat;
import java.util.Date;
import jp.agentec.abook.abv.bl.common.log.Logger;
/**
* Information class of media file
*/
public class ImageInfo {
private static final String TAG = "ImageInfo";
public static String FILE_FORMAT_CODE_EXIF_JPEG = "JPEG";
public static String FILE_FORMAT_CODE_EXIF_MPEG = "MPEG";
private String mFileName;
private String mFileId;
private long mFileSize;
private String mCaptureDate;
private String mFileFormat;
private int mWidth;
private int mHeight;
/**
* Acquire file name
* @return File name
*/
public String getFileName() {
return mFileName;
}
/**
* Set file name
* @param fileName File name
*/
public void setFileName(String fileName) {
mFileName = fileName;
}
/**
* Acquire File ID
* @return File ID
*/
public String getFileId() {
return mFileId;
}
/**
* Set File ID
* @param fileId File ID
*/
public void setFileId(String fileId) {
mFileId = fileId;
}
/**
* Acquire file size
* @return File size (unit: bytes)
*/
public long getFileSize() {
return mFileSize;
}
/**
* Set file size
* @param fileSize File size (unit: bytes)
*/
public void setFileSize(long fileSize) {
mFileSize = fileSize;
}
/**
* Acquire shooting time
* @return Shooting time
*/
public String getCaptureDate() {
return mCaptureDate;
}
/**
* Set shooting time
* @param captureDate Shooting time
*/
public void setCaptureDate(String captureDate) {
String createDateStr = null;
if (captureDate.length() > 20) {
//文字列の最後のタイムゾーン情報+09:00除外
createDateStr = captureDate.substring(0, captureDate.length() - 6);
} else {
createDateStr = captureDate;
}
try {
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
Date date = sdFormat.parse(createDateStr);
mCaptureDate = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(date);
} catch (Exception e) {
Logger.e(TAG, e.toString());
}
}
/**
* Acquire media format
* @return Media format
*/
public String getFileFormat() {
return mFileFormat;
}
/**
* Set media format<p>
* Set {@link ImageInfo#FILE_FORMAT_CODE_EXIF_JPEG} or {@link ImageInfo#FILE_FORMAT_CODE_EXIF_MPEG}.
* @param fileFormat Media format
*/
public void setFileFormat(String fileFormat) {
mFileFormat = fileFormat;
}
/**
* Acquire image width
* @return Image width
*/
public int getWidth() {
return mWidth;
}
/**
* Set image width
* @param width Image width
*/
public void setWidth(int width) {
mWidth = width;
}
/**
* Acquire image height
* @return Image height
*/
public int getHeight() {
return mHeight;
}
/**
* Set image height
* @param height Image height
*/
public void setHeight(int height) {
mHeight = height;
}
}
package com.theta.network;
/**
* Information class of device storage
*/
public class StorageInfo {
int mRemainingPictures = 0;
long mRemainingSpace = 0;
long mTotalSpace = 0;
/**
* Acquire remaining number of images that can be shot
* @return Remaining number of images that can be shot
*/
public int getFreeSpaceInImages() {
return mRemainingPictures;
}
/**
* Set remaining number of images that can be shot
* @param remainingPictures Remaining number of images that can be shot
*/
public void setFreeSpaceInImages(int remainingPictures) {
mRemainingPictures = remainingPictures;
}
/**
* Acquire remaining capacity
* @return Remaining capacity (unit: bytes)
*/
public long getFreeSpaceInBytes() {
return mRemainingSpace;
}
/**
* Set remaining capacity
* @param remainingSpace Remaining capacity (unit: bytes)
*/
public void setFreeSpaceInBytes(long remainingSpace) {
mRemainingSpace = remainingSpace;
}
/**
* Acquire total capacity of device
* @return Total capacity of device (unit: bytes)
*/
public long getMaxCapacity() {
return mTotalSpace;
}
/**
* Set total capacity of device
* @param totalSpace Total capacity of device (unit: bytes)
*/
public void setMaxCapacity(long totalSpace) {
mTotalSpace = totalSpace;
}
}
package com.theta.network;
/**
* Device information class
*/
public class ThetaDeviceInfo {
private String mModel = "";
private String mDeviceVersion = "";
private String mSerialNumber = "";
private String mSSID = "";
private int mNetworkId = -1;
/**
* Constructor
*/
public ThetaDeviceInfo() {
}
/**
* Acquire model name
* @return Model name
*/
public String getModel() {
return mModel;
}
/**
* Set model name
* @param model Model name
*/
public void setModel(String model) {
mModel = model;
}
/**
* Acquire serial number
* @return Serial number
*/
public String getSerialNumber() {
return mSerialNumber;
}
/**
* Set serial number
* @param serialNumber Serial number
*/
public void setSerialNumber(String serialNumber) {
mSerialNumber = serialNumber;
}
/**
* Acquire firmware version
* @return Firmware version
*/
public String getDeviceVersion() {
return mDeviceVersion;
}
/**
* Set firmware version
* @param version Firmware version
*/
public void setDeviceVersion(String version) {
mDeviceVersion = version;
}
/**
* Acquire SSID
* @return SSID
*/
public String getSSID() {
return mSSID;
}
/**
* Set SSID
* @param ssid SSID
*/
public void setSSID(String ssid) {
mSSID = ssid;
}
/**
* Acquire network ID
* @return network ID
*/
public int getNetworkId() {
return mNetworkId;
}
/**
* Set network ID
* @param networkId network ID
*/
public void setNetworkId(int networkId) {
mNetworkId = networkId;
}
}
package com.theta.network;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.StringReader;
/**
* XMP data class
*/
public class XMP {
private final static String XMP_START_ELEMENT = "<x:xmpmeta";
private final static String XMP_END_ELEMENT = "</x:xmpmeta>";
private final static String XMP_TAG_NAME_PITCH = "PosePitchDegrees";
private final static String XMP_TAG_NAME_ROLL = "PoseRollDegrees";
private Double mPosePitchDegrees;
private Double mPoseRollDegrees;
/**
* Constructor
* @param original Raw data of image
*/
public XMP(byte[] original) {
int startXmpIndex = indexOf(original, XMP_START_ELEMENT.getBytes(), 0);
int endXmpIndex = indexOf(original, XMP_END_ELEMENT.getBytes(), startXmpIndex);
String xmpData = new String(original, startXmpIndex, endXmpIndex - startXmpIndex + XMP_END_ELEMENT.length());
XmlPullParser parser = Xml.newPullParser();
try {
parser.setInput(new StringReader(xmpData));
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
String tagName = parser.getName();
if (tagName.equals(XMP_TAG_NAME_PITCH)) {
String pitchInXml = parser.nextText();
mPosePitchDegrees = Double.valueOf(pitchInXml);
} else if (tagName.equals(XMP_TAG_NAME_ROLL)) {
String rollInXml = parser.nextText();
mPoseRollDegrees = Double.valueOf(rollInXml);
}
break;
case XmlPullParser.START_DOCUMENT:
case XmlPullParser.END_TAG:
case XmlPullParser.TEXT:
// do nothing
break;
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Acquire pitch angle set for XMP
* @return Pitch angle
*/
public Double getPosePitchDegrees() {
return mPosePitchDegrees;
}
/**
* Acquire roll angle set for XMP
* @return Roll angle
*/
public Double getPoseRollDegrees() {
return mPoseRollDegrees;
}
/**
* Search position of specific data pattern
* @param original Search target data
* @param sub Searched data
* @param startIndex Search start position
* @return The position where the searched data starts. "-1" is returned if there are no hits.
*/
private int indexOf(byte[] original, byte[] sub, int startIndex)
{
int subIndex = 0;
for(int originalIndex = startIndex; originalIndex < original.length; originalIndex++) {
if(original[originalIndex] == sub[subIndex]) {
if(subIndex == sub.length - 1) {
return originalIndex - subIndex;
}
subIndex++;
} else {
subIndex = 0;
}
}
return -1;
}
}
package com.theta.view;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
import jp.agentec.abook.abv.launcher.android.R;
/**
* Adapter class for photo list display
*/
public class ImageListArrayAdapter extends ArrayAdapter<ImageRow> {
private List<ImageRow> rows;
private LayoutInflater inflater;
private boolean isPhone;
/**
* Constructor
* @param context Context
* @param resourceIdOfListLayout Resource ID for specifying line information
* @param rows Line object
*/
public ImageListArrayAdapter(Context context, int resourceIdOfListLayout, List<ImageRow> rows, boolean isPhone) {
super(context, resourceIdOfListLayout, rows);
this.rows = rows;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.isPhone = isPhone;
}
/**
* getView Method
* @param position Acquisition position
* @param convertView convertView object
* @param parent Parent object for list
* @return View instance
*/
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = inflater.inflate(R.layout.listlayout_object, null);
holder = new ViewHolder();
holder.thumbnail = convertView.findViewById(R.id.object_thumbnail);
holder.fileNameTextView = convertView.findViewById(R.id.tv_file_name);
holder.creatDateTextView = convertView.findViewById(R.id.tv_create_date);
holder.saveButton = convertView.findViewById(R.id.btn_theta_image_save);
holder.deleteButton = convertView.findViewById(R.id.btn_theta_image_delete);
holder.transferredTextView = convertView.findViewById(R.id.tv_transferred_status);
convertView.setTag(holder);
//スマートフォンの場合、サイズ調整
if (isPhone) {
resizeView(holder.thumbnail, 0.6f);
resizeView(holder.saveButton, 0.7f);
resizeView(holder.deleteButton, 0.7f);
}
} else {
holder = (ViewHolder) convertView.getTag();
}
final ImageRow row = rows.get(position);
if (row.isPhoto()) {
byte[] thumbnailImage = row.getThumbnail();
holder.thumbnail.setImageBitmap(BitmapFactory.decodeByteArray(thumbnailImage, 0, thumbnailImage.length));
} else {
holder.thumbnail.setImageBitmap(null);
}
holder.fileNameTextView.setText(row.getFileName());
holder.creatDateTextView.setText(row.getCaptureDate());
holder.saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((ListView) parent).performItemClick(v, position, R.id.btn_theta_image_save);
}
});
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((ListView) parent).performItemClick(v, position, R.id.btn_theta_image_save);
}
});
if (row.isTransferred()) {
holder.transferredTextView.setVisibility(View.VISIBLE);
} else {
holder.transferredTextView.setVisibility(View.INVISIBLE);
}
return convertView;
}
/**
* ImageView, Buttonサイズ調整
* @param view (ImageView, Button)
* @param scale サイズ調整率
*/
private void resizeView(View view, float scale) {
ViewGroup.LayoutParams params = view.getLayoutParams();
//サイズに変更
params.width = (int) (params.width * scale);
if (view instanceof ImageView) {
params.height = (int) (params.height * scale);
}
view.setLayoutParams(params);
}
public void setListItem(List<ImageRow> changeRows) {
this.rows = changeRows;
}
static class ViewHolder {
Button deleteButton;
Button saveButton;
TextView fileNameTextView;
TextView creatDateTextView;
TextView transferredTextView;
ImageView thumbnail;
}
}
package com.theta.view;
/**
* Line object for list when photo list is displayed
*/
public class ImageRow {
private String fileId;
private long fileSize;
private boolean isPhoto;
private byte[] thumbnail;
private String fileName;
private String captureDate;
private boolean isTransferred;
/**
* Identifier value acquisition method for photo object
* @return Handle value for photo object
*/
public String getFileId() {
return fileId;
}
/**
* Identifier value setting method for photo object
* @param fileId identifier value for photo object
*/
public void setFileId(String fileId) {
this.fileId = fileId;
}
/**
* Acquire file size
* @return File size
*/
public long getFileSize() {
return fileSize;
}
/**
* Set file size
* @param fileSize File size
*/
public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}
/**
* Photo information feasibility value acquisition method
* @return Photo information feasibility value
*/
public boolean isPhoto() {
return isPhoto;
}
/**
* Photo information feasibility value setting method
* @param isPhoto Photo information feasibility value
*/
public void setIsPhoto(boolean isPhoto) {
this.isPhoto = isPhoto;
}
/**
* Thumbnail information acquisition method
* @return Thumbnail information
*/
public byte[] getThumbnail() {
return thumbnail;
}
/**
* Thumbnail information setting method
* @param thumbnail Thumbnail information
*/
public void setThumbnail(byte[] thumbnail) {
this.thumbnail = thumbnail;
}
/**
* File name acquisition method
* @return File name
*/
public String getFileName() {
return fileName;
}
/**
* File name setting method
* @param fileName File name
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* Capture date and time acquisition method
* @return Capture date and time
*/
public String getCaptureDate() {
return captureDate;
}
/**
* Capture date and time setting method
* @param captureDate Capture date and time
*/
public void setCaptureDate(String captureDate) {
this.captureDate = captureDate;
}
/**
* Photo Transferred value value acquisition method
* @return Photo Transferred value
*/
public boolean isTransferred() {
return isTransferred;
}
/**
* Photo Transferred value value setting method
* @param isTransferred Photo Transferred value
*/
public void setIsTransferred(boolean isTransferred) {
this.isTransferred = isTransferred;
}
}
package com.theta.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
import android.widget.TextView;
/**
* View for log display
*/
public class LogView extends ScrollView {
private TextView textView;
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/**
* Constructor
* @param context Context
* @param attrs Argument for resource
*/
public LogView(Context context, AttributeSet attrs) {
super(context, attrs);
setFillViewport(true);
textView = new TextView(context);
textView.setBackgroundResource(android.R.color.darker_gray);
textView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
this.addView(textView);
}
/**
* Log output request method
* @param newLine Output log
*/
public void append(CharSequence newLine) {
textView.append(newLine);
textView.append(LINE_SEPARATOR);
fullScroll(FOCUS_DOWN);
}
}
package com.theta.view;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* Input stream for motion JPEG data
*/
public class MJpegInputStream extends DataInputStream {
private final byte[] SOI_MARKER = {(byte) 0xFF, (byte) 0xD8};
private final byte[] EOF_MARKER = {(byte) 0xFF, (byte) 0xD9};
private final static String CONTENT_LENGTH = "Content-Length";
private final static int HEADER_MAX_LENGTH = 100;
private final static int FRAME_MAX_LENGTH = 40000 + HEADER_MAX_LENGTH;
/**
* Constructor
* @param inputStream Input stream for receiving data
*/
public MJpegInputStream(InputStream inputStream) {
super(new BufferedInputStream(inputStream, FRAME_MAX_LENGTH));
}
/**
* Acquire end position of specified character string
* @param dataInputStream Input stream for receiving data
* @param sequence Specified character string
* @return End position of specified character string
* @throws IOException
*/
private int getEndOfSequence(DataInputStream dataInputStream, byte[] sequence) throws IOException {
int sequenceIndex = 0;
byte readByteData;
for(int index = 0; index < FRAME_MAX_LENGTH; index++) {
readByteData = (byte) dataInputStream.readUnsignedByte();
if(readByteData == sequence[sequenceIndex]) {
sequenceIndex++;
if(sequenceIndex == sequence.length) {
return index + 1;
}
} else {
sequenceIndex = 0;
}
}
return -1;
}
/**
* Acquire start position of specified character string
* @param dataInputStream Input stream for receiving data
* @param sequence Specified character string
* @return Start position of specified character string
* @throws IOException
*/
private int getStartOfSequence(DataInputStream dataInputStream, byte[] sequence) throws IOException {
int endIndex = getEndOfSequence(dataInputStream, sequence);
return (endIndex < 0) ? (-1) : (endIndex - sequence.length);
}
/**
* Acquire data length from header
* @param headerByteData Header data
* @return Data length
* @throws IOException
* @throws NumberFormatException
*/
private int parseContentLength(byte[] headerByteData) throws IOException, NumberFormatException {
ByteArrayInputStream bais = new ByteArrayInputStream(headerByteData);
Properties properties = new Properties();
properties.load(bais);
return Integer.parseInt(properties.getProperty(CONTENT_LENGTH));
}
/**
* Acquire image data for 1 frame
* @return Image data for 1 frame
* @throws IOException
*/
public Bitmap readMJpegFrame() throws IOException {
mark(FRAME_MAX_LENGTH);
int headerLength = getStartOfSequence(this, SOI_MARKER);
int contentLength;
reset();
byte[] headerData = new byte[headerLength];
readFully(headerData);
try {
contentLength = parseContentLength(headerData);
} catch (NumberFormatException e) {
e.getStackTrace();
contentLength = getEndOfSequence(this, EOF_MARKER);
}
reset();
byte[] frameData = new byte[contentLength];
skipBytes(headerLength);
readFully(frameData);
return BitmapFactory.decodeStream(new ByteArrayInputStream(frameData));
}
}
package com.theta.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
/**
* Motion JPEG view
*/
public class MJpegView extends SurfaceView implements SurfaceHolder.Callback {
private MJpegViewThread mMJpegViewThread = null;
private MJpegInputStream mMJpegInputStream = null;
private boolean existSurface = false;
private int mDisplayWidth;
private int mDisplayHeight;
/**
* Constructor
* @param context
*/
public MJpegView(Context context) {
super(context);
init();
}
/**
* Constructor
* @param context
* @param attrs
*/
public MJpegView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* Constructor
* @param context
* @param attrs
* @param defStyleAttr
*/
public MJpegView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* Initialization process
*/
private void init() {
SurfaceHolder holder = getHolder();
holder.addCallback(this);
setFocusable(true);
mDisplayWidth = getWidth();
mDisplayHeight = getHeight();
}
/**
* Start playback
*/
public void play() {
if (mMJpegViewThread != null) {
stopPlay();
}
if(mMJpegInputStream != null) {
if (mMJpegViewThread != null) {
if (mMJpegViewThread.getState() == Thread.State.NEW) {
mMJpegViewThread.start();
}
} else {
mMJpegViewThread = new MJpegViewThread(getHolder());
mMJpegViewThread.start();
}
}
}
/**
* Stop playback
*/
public void stopPlay() {
if (mMJpegViewThread != null) {
mMJpegViewThread.cancel();
boolean retry = true;
while (retry) {
try {
mMJpegViewThread.join();
retry = false;
mMJpegViewThread = null;
} catch (InterruptedException e) {
e.getStackTrace();
}
}
}
}
/**
* Set source stream for receiving motion JPEG
* @param source Source stream
*/
public void setSource(MJpegInputStream source) {
mMJpegInputStream = source;
play();
}
/**
* Get source stream for receiving motion JPEG
* @return Source stream
*/
public MJpegInputStream getSource() {
return mMJpegInputStream;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
existSurface = true;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
synchronized(holder) {
mDisplayWidth = width;
mDisplayHeight = height;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
existSurface = false;
stopPlay();
}
/**
* Thread class for receiving motion JPEG
*/
private class MJpegViewThread extends Thread {
private final SurfaceHolder mSurfaceHolder;
private boolean keepRunning = true;
/**
* Constructor
* @param surfaceHolder
*/
public MJpegViewThread(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
}
/**
* Acquire image size according to display area<p>
* Calculates the size that fits the display area while maintaining the aspect ratio of the motion JPEG.
* @param bitmapWidth Width of motion JPEG
* @param bitmapHeight Height of motion JPEG
* @return Image size
*/
private Rect getImageRect(int bitmapWidth, int bitmapHeight) {
float bitmapAspectRatio = (float) bitmapWidth / (float) bitmapHeight;
bitmapWidth = mDisplayWidth;
bitmapHeight = (int) (mDisplayWidth / bitmapAspectRatio);
if (bitmapHeight > mDisplayHeight) {
bitmapHeight = mDisplayHeight;
bitmapWidth = (int) (mDisplayHeight * bitmapAspectRatio);
}
int bitmapX = (mDisplayWidth / 2) - (bitmapWidth / 2);
int bitmapY = (mDisplayHeight / 2) - (bitmapHeight / 2);
return new Rect(0, bitmapY, mDisplayWidth, bitmapHeight + bitmapY);
}
/**
* Abort thread
*/
public void cancel() {
keepRunning = false;
}
@Override
public void run() {
Bitmap bitmap;
Rect bitmapRect;
Canvas bitmapCanvas = null;
while (keepRunning) {
if (existSurface) {
try {
bitmapCanvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
try {
if ((mMJpegInputStream != null) && (bitmapCanvas != null)) {
bitmap = mMJpegInputStream.readMJpegFrame();
bitmapRect = getImageRect(bitmap.getWidth(), bitmap.getHeight());
bitmapCanvas.drawColor(Color.BLACK);
bitmapCanvas.drawBitmap(bitmap, null, bitmapRect, new Paint());
bitmap.recycle();
}
} catch (IOException e) {
e.getStackTrace();
keepRunning = false;
}
}
} finally {
if (bitmapCanvas != null) {
mSurfaceHolder.unlockCanvasAndPost(bitmapCanvas);
}
}
}
}
bitmapCanvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
if (bitmapCanvas != null) {
bitmapCanvas.drawColor(Color.BLACK);
}
}
if (bitmapCanvas != null) {
mSurfaceHolder.unlockCanvasAndPost(bitmapCanvas);
}
if (mMJpegInputStream != null) {
try {
mMJpegInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
......@@ -13,7 +13,9 @@ import android.os.Build;
import android.os.Debug;
import android.os.Environment;
import android.os.StatFs;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.text.TextUtils;
import android.util.Base64;
import android.view.Display;
import android.view.WindowManager;
......@@ -253,4 +255,40 @@ public class DeviceInfo {
//noinspection deprecation(API18から非推奨になった。無視)
return (long)stat.getBlockSize() * stat.getAvailableBlocks();
}
/**
* デバイスのWifi有効・無効チェック
* @return true:有効, false:無効
*/
public static boolean isDeviceWifiEnabled(Context context) {
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager == null) {
return false;
}
return wifiManager.isWifiEnabled();
}
/**
* 端末の位置情報機能の有無チェック
* @return true:位置情報機能ON, false:位置情報機能OFF
*/
public static boolean isDeviceLocationEnabled(Context context) {
int locationMode = 0;
String locationProviders;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
try {
locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
return false;
}
return locationMode != Settings.Secure.LOCATION_MODE_OFF;
}else{
locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return !TextUtils.isEmpty(locationProviders);
}
}
}
......@@ -169,6 +169,14 @@ public abstract class ABVActivity extends Activity {
showProgressPopup(getResources().getString(R.string.progress));
}
public void changeProgressPopup(String msg) {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.setMessage(msg);
} else {
showProgressPopup(msg);
}
}
public void closeProgressPopup() {
handler.post(new Runnable() {
@Override
......@@ -483,31 +491,42 @@ public abstract class ABVActivity extends Activity {
}
/**
* 前回の端末利用から一定期間が経っているかどうかチェックする
* 前回の端末利用から一定期間が経っているかどうかチェックし、ログイン画面表示
* @return true:認証有効 false:認証無効
*/
protected boolean checkValidAuthTime() {
boolean result = false;
try {
// サービスオプションチェック
if (AbstractLogic.getLogic(ContractLogic.class).getForceLoginPeriodically()) {
long leavedAppTime = getUserPref(UserPrefKey.LEAVE_APP, -1L);
if (leavedAppTime != -1) {
Date leavedAppDate = new Date(leavedAppTime);
Date currentDate = new Date(System.currentTimeMillis());
if (currentDate.after(DateTimeUtil.add(leavedAppDate, DateUnit.Day, ABVEnvironment.LastLoginExpiryDate))) {
callLoginActivity(false, true, false);
result = true;
}
}
if (checkForceLoginPeriodically()) {
callLoginActivity(false, true, false);
result = true;
}
} catch (Exception e) {
result = false;
Logger.e("Exception LoginTimeOutCheck", e);
}
return result;
}
/**
* @version 1.2.300
* 一定期間(90日)アプリロックチェック
* @return true:アプリロックする、false:アプリロックしない
*/
protected boolean checkForceLoginPeriodically() {
// サービスオプションチェック
if (AbstractLogic.getLogic(ContractLogic.class).getForceLoginPeriodically()) {
long leavedAppTime = getUserPref(UserPrefKey.LEAVE_APP, -1L);
if (leavedAppTime != -1) {
Date leavedAppDate = new Date(leavedAppTime);
Date currentDate = new Date(System.currentTimeMillis());
if (currentDate.after(DateTimeUtil.add(leavedAppDate, DateUnit.Day, ABVEnvironment.LastLoginExpiryDate))) {
return true;
}
}
}
return false;
}
// 一定期間経過後強制ログアウトチェック
protected boolean checkForceOfflineLogout() {
boolean result = false;
......@@ -796,6 +815,13 @@ public abstract class ABVActivity extends Activity {
PreferenceUtil.putUserPref(this, UserPrefKey.LEAVE_APP, System.currentTimeMillis());
}
public void showSimpleAlertDialog(final int bodyId) {
showSimpleAlertDialog(getString(R.string.app_name), getString(bodyId));
}
public void showSimpleAlertDialog(final String body) {
showSimpleAlertDialog(getString(R.string.app_name), body);
}
public void showSimpleAlertDialog(final int titleResId, final int bodyResId) {
showSimpleAlertDialog(getString(titleResId), getString(bodyResId));
}
......@@ -966,4 +992,21 @@ public abstract class ABVActivity extends Activity {
}
return true;
}
/**
* ネットワークチェックして非接続時にダイアログ表示
* @return true:接続、false:非接続
*/
protected boolean checkNetworkConnected() {
if (!ABVEnvironment.getInstance().networkAdapter.isNetworkConnected()) {
handler.post(new Runnable() {
@Override
public void run() {
showSimpleAlertDialog(R.string.app_name, R.string.msg_network_offline);
}
});
return false;
}
return true;
}
}
......@@ -115,6 +115,9 @@ public abstract class ABVAuthenticatedActivity extends ABVActivity implements Co
public static final String FILEPATH = "FILEPATH";
//連続タップ防止用のボタン活性化するタイム
protected static final int BUTTON_ENABLE_DELAY_MILLIS = 500;
protected ContentDao contentDao = AbstractDao.getDao(ContentDao.class);
protected MemoLogic memoLogic = AbstractLogic.getLogic(MemoLogic.class);
......@@ -500,7 +503,10 @@ public abstract class ABVAuthenticatedActivity extends ABVActivity implements Co
configureKeepScreen();
}
if (e != null) {
handleError(e);
//新着更新時にログアウトすることで、SIDが取得できなく、例外が発生したときにはトースト非表示
if (ABVDataCache.getInstance().getMemberInfo() != null) {
handleError(e);
}
}
}
});
......@@ -737,6 +743,7 @@ public abstract class ABVAuthenticatedActivity extends ABVActivity implements Co
ErrorMessage.showErrorMessageToast(ABVAuthenticatedActivity.this, error);
}
}
public void showUnAuthorizedContentWarningDialog(String msg) {
ABookAlertDialog alertDialog = AlertDialogUtil.createAlertDialog(this, getString(R.string.app_name), msg);
alertDialog.setPositiveButton(R.string.ok, null);
......@@ -765,4 +772,28 @@ public abstract class ABVAuthenticatedActivity extends ABVActivity implements Co
public boolean isShowingBatchSync() {
return batchSyncView != null && batchSyncView.isShowing();
}
/**
* @version 1.2.300
* 新着情報更新処理を中止
*/
public void stopContentRefresher() {
contentRefresher.stopRefresh();
}
/**
* @version 1.2.300
* ダブルタップ制御用
* @param button ダブルタップ防止ボタン
*/
protected void buttonDoubleTapControl(Button button) {
final Button finalButton = button;
finalButton.setEnabled(false);
handler.postDelayed(new Runnable() {
@Override
public void run() {
finalButton.setEnabled(true);
}
}, BUTTON_ENABLE_DELAY_MILLIS);
}
}
......@@ -90,7 +90,6 @@ public abstract class ABVContentViewActivity extends ABVAuthenticatedActivity {
private static final String TAG ="ABVContentViewActivity";
public final static int ABOOK_CHECK_TASK_IMAGE = 103;
public final static int ABOOK_CHECK_TASK_VIDEO = 104;
protected final static int ABOOK_CHECK_SELECT_SCENE = 105;
protected long contentId;// 表示中のコンテンツID
protected long objectId; // オブジェクトID(オブジェクト用のActivityのときのみ使用)
......
......@@ -21,6 +21,7 @@ import jp.agentec.abook.abv.bl.dto.OperationDto;
import jp.agentec.abook.abv.bl.dto.PushMessageDto;
import jp.agentec.abook.abv.bl.logic.AbstractLogic;
import jp.agentec.abook.abv.bl.logic.PushMessageLogic;
import jp.agentec.abook.abv.cl.environment.DeviceInfo;
import jp.agentec.abook.abv.cl.helper.ContentMarkingFileHelper;
import jp.agentec.abook.abv.cl.util.AndroidStringUtil;
import jp.agentec.abook.abv.launcher.android.ABVApplication;
......@@ -40,6 +41,7 @@ import jp.agentec.abook.abv.ui.home.adapter.FixPushMessageAdapter;
import jp.agentec.abook.abv.ui.home.adapter.OperationSelectAdapter;
import jp.agentec.abook.abv.ui.home.adapter.PushMessageListAdapter;
import jp.agentec.abook.abv.ui.home.helper.ActivityHandlingHelper;
import jp.agentec.abook.abv.ui.viewer.activity.DeviceImageListActivity;
import jp.agentec.adf.util.DateTimeFormat;
import jp.agentec.adf.util.DateTimeUtil;
......@@ -72,6 +74,12 @@ import java.util.List;
public abstract class ABVUIActivity extends ABVAuthenticatedActivity {
private final static String TAG = "ABVUIActivity";
//タブレットでダイアログ表示の画面サイズ調整スケール
protected static final float DIALOG_WINDOW_RESIZE_SCALE_06 = 0.6f;
protected static final float DIALOG_WINDOW_RESIZE_SCALE_07 = 0.7f;
protected static final float DIALOG_WINDOW_RESIZE_SCALE_08 = 0.8f;
protected static final float DIALOG_WINDOW_RESIZE_SCALE_09 = 0.9f;
private boolean startRefresh; //自動リフレッシュはネットワークエラー表示しないように
protected ImageView mRefreshImage; // add by jang
protected TextView mUpdatedDate; // add by jang
......@@ -442,9 +450,12 @@ public abstract class ABVUIActivity extends ABVAuthenticatedActivity {
}
});
}
// 自動ダウンロード対象がある場合、新着更新が完了したあとに開始するように修正(jang)
ContentDownloader.getInstance().autoDownload();
//ログアウト時にも呼ばれるのでチェック
ABVDataCache cache = ABVDataCache.getInstance();
if (cache.getMemberInfo() != null) {
// 自動ダウンロード対象がある場合、新着更新が完了したあとに開始するように修正(jang)
ContentDownloader.getInstance().autoDownload();
}
}
/**
......@@ -941,4 +952,18 @@ public abstract class ABVUIActivity extends ABVAuthenticatedActivity {
}
return existUnreadFlg;
}
/**
* デバイスのWifi有効・無効チェックし
* 無効の場合、ダイアログ表示
* @return true:有効, false:無効
*/
protected boolean deviceWifiEnable() {
if (DeviceInfo.isDeviceWifiEnabled(this)) {
return true;
} else {
showSimpleAlertDialog(R.string.msg_error_device_wifi_off);
return false;
}
}
}
package jp.agentec.abook.abv.ui.common.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
import jp.agentec.abook.abv.launcher.android.R;
public class SimpleTextViewAdapter extends BaseAdapter {
private List<String> mListItem;
private LayoutInflater mInflater;
public SimpleTextViewAdapter(Context context, List<String> listItem) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.mListItem = listItem;
}
@Override
public int getCount() {
return mListItem.size();
}
@Override
public Object getItem(int position) {
return mListItem.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_simple_textview, null);
}
TextView textView = convertView.findViewById(R.id.tv_item);
textView.setText(mListItem.get(position));
return convertView;
}
}
......@@ -3,6 +3,7 @@ import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.dialog.ABookAlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.FrameLayout;
......@@ -41,7 +42,60 @@ public class AlertDialogUtil {
alertDialog.setMessage(message);
return alertDialog;
}
/**
* 共通ダイアログ表示用(Cancel表示・非表示、OKボタンコールバック)
* @param context コンテキスト
* @param title タイトル 文字列
* @param message メッセージ 文字列
* @param isCancleButtonHidden Cancelボタン表示(false)・非表示(true)
* @param okOnClick OKボタンコールバック
*/
public static void showAlertDialog(Context context, String title, String message, boolean isCancleButtonHidden, DialogInterface.OnClickListener okOnClick) {
ABookAlertDialog alertDialog = createAlertDialog(context, title, message);
if (!isCancleButtonHidden) {
alertDialog.setNegativeButton(R.string.cancel, null);
}
alertDialog.setCancelable(false);
alertDialog.setPositiveButton(R.string.ok, okOnClick);
alertDialog.show();
}
/**
* 共通ダイアログ表示用(OKボタンコールバック、CANCELボタンコールバック)
* @param context コンテキスト
* @param title タイトル
* @param message メッセージ
* @param okOnClick OKボタンコールバック
* @param okOnClick CANCELボタンコールバック
*/
public static void showAlertDialog(Context context, int title, int message, DialogInterface.OnClickListener okOnClick, DialogInterface.OnClickListener canOnClick) {
ABookAlertDialog alertDialog = createAlertDialog(context, context.getResources().getString(title), context.getResources().getString(message));
alertDialog.setNegativeButton(R.string.cancel, canOnClick);
alertDialog.setPositiveButton(R.string.ok, okOnClick);
alertDialog.setCancelable(false);
alertDialog.show();
}
/**
* 共通ダイアログ表示用(Cancel表示・非表示、OKボタンコールバック)
* @param context コンテキスト
* @param title タイトル
* @param message メッセージ
* @param isCancleButtonHidden Cancelボタン表示(false)・非表示(true)
* @param okOnClick OKボタンコールバック
*/
public static void showAlertDialog(Context context, int title, int message, boolean isCancleButtonHidden, DialogInterface.OnClickListener okOnClick) {
ABookAlertDialog alertDialog = createAlertDialog(context, context.getResources().getString(title), context.getResources().getString(message));
if (!isCancleButtonHidden) {
alertDialog.setNegativeButton(R.string.cancel, null);
}
alertDialog.setCancelable(false);
alertDialog.setPositiveButton(R.string.ok, okOnClick);
alertDialog.show();
}
public static ABookAlertDialog deleteContentAlertDialog(Context context, int deleteMessage) {
ABookAlertDialog alertDialog = createAlertDialog(context, R.string.delete);
alertDialog.setMessage(deleteMessage);
......
......@@ -83,4 +83,8 @@ public class ABookSettingActivity extends PreferenceActivity {
return (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_NORMAL;
}
public void stopContentRefresher() {
ABVUIActivity activity = ActivityHandlingHelper.getInstance().getPreviousOfSettingActivity();
activity.stopContentRefresher();
}
}
......@@ -35,7 +35,6 @@ import jp.agentec.abook.abv.bl.acms.type.AcmsApis;
import jp.agentec.abook.abv.bl.common.ABVEnvironment;
import jp.agentec.abook.abv.bl.common.CommonExecutor;
import jp.agentec.abook.abv.bl.common.Constant;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.data.ABVDataCache;
import jp.agentec.abook.abv.bl.dto.MemberInfoDto;
......@@ -49,19 +48,14 @@ 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;
import jp.agentec.abook.abv.ui.common.appinfo.AppDefType.UserPrefKey;
import jp.agentec.abook.abv.ui.common.appinfo.options.Options;
import jp.agentec.abook.abv.ui.common.dialog.ABookAlertDialog;
import jp.agentec.abook.abv.ui.common.helper.ProgressDialogHelper;
import jp.agentec.abook.abv.ui.common.util.ABVToastUtil;
import jp.agentec.abook.abv.ui.common.util.AlertDialogUtil;
import jp.agentec.abook.abv.ui.common.util.PatternStringUtil;
import jp.agentec.abook.abv.ui.home.helper.ABookPermissionHelper;
import jp.agentec.adf.util.DateTimeFormat;
import jp.agentec.adf.util.DateTimeUtil;
import static jp.agentec.abook.abv.cl.util.PreferenceUtil.getUserPref;
import static jp.agentec.abook.abv.cl.util.PreferenceUtil.putUserPref;
public class ABookSettingFragment extends PreferenceFragment {
private static final String TAG = "ABookSettingActivity";
......@@ -191,6 +185,9 @@ public class ABookSettingFragment extends PreferenceFragment {
ABVToastUtil.showMakeText(getActivity(), R.string.ERROR, Toast.LENGTH_SHORT);
}
// 新着更新が実行されている場合停止
((ABookSettingActivity)getActivity()).stopContentRefresher();
SharedPreferences sharedPreferences = getActivity().getSharedPreferences(AppDefType.PrefName.USER_PREFERENCE, Context.MODE_PRIVATE);
sharedPreferences.edit().remove(AppDefType.UserPrefKey.GUEST_LOGIN).commit();
......
......@@ -15,6 +15,8 @@ import jp.agentec.abook.abv.bl.common.exception.ABVExceptionCode;
import jp.agentec.abook.abv.bl.common.exception.AcmsException;
import jp.agentec.abook.abv.bl.common.exception.NetworkDisconnectedException;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.common.util.SecurityUtil;
import jp.agentec.abook.abv.bl.data.ABVDataCache;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.AcmsDao;
import jp.agentec.abook.abv.bl.data.dao.MemberInfoDao;
......@@ -171,6 +173,10 @@ public class LoginActivity extends ABVLoginActivity {
// 一定時間経過後、アプリロックか強制ログアウトの状態かチェックする
oldMemberInfoDto = AbstractDao.getDao(MemberInfoDao.class).getMemberInfo();
if (oldMemberInfoDto != null) {
//サービスオプション情報をキャッシュにセット
final ABVDataCache dataCache = ABVDataCache.getInstance();
dataCache.refreshServiceOptions();
// ユーザが一定時間経過後アプリロックの状態であるかチェック
if (oldMemberInfoDto.loginStatus == LoginStatus.LimitLogin.statusCode()) {
mEdtLoginId.setText(oldMemberInfoDto.loginId);
......@@ -302,6 +308,12 @@ public class LoginActivity extends ABVLoginActivity {
if (validate()) {
boolean agree_macInfor;
//アプリロック状態でインターネット非接続時に正常なパスワード入力しても解除できない問題対応
if (oldMemberInfoDto != null && oldMemberInfoDto.loginStatus == LoginStatus.LimitLogin.statusCode()) {
// アプリロックの場合サーバ認証せずにログイン
offlineLogin();
return;
}
agree_macInfor = getUserPref(UserPrefKey.AGREE_MACINFO, false);
// Macアドレスに既に同意している場合、ログイン
int deviceIdType = Constant.DeviceIdType.MAC_ADDRESS;
......@@ -386,12 +398,7 @@ public class LoginActivity extends ABVLoginActivity {
CommonExecutor.execute(new Runnable() {
@Override
public void run() {
if (oldMemberInfoDto != null && oldMemberInfoDto.loginStatus == LoginStatus.LimitLogin.statusCode()) {
// アプリロックの場合サーバ認証せずにログイン
offlineLogin();
} else {
fcmRegister();
}
fcmRegister();
}
});
}
......@@ -516,6 +523,7 @@ public class LoginActivity extends ABVLoginActivity {
// パスワード変更の状況に合わせてログインステータスの書き換え
dto.loginStatus = userAuthenticateLogic.convertLoginStatusFromChangePasswordType(changePasswordType);
dto.password = SecurityUtil.getEncriptPassword(dto.password, dto.loginId);
userAuthenticateLogic.saveMemberInfo(dto, mUrlPath);
if (changePasswordType == RequirePasswordChangeType.NONE) {
......
......@@ -21,6 +21,7 @@ import jp.agentec.abook.abv.ui.common.util.AlertDialogUtil;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.util.PatternStringUtil;
import jp.agentec.abook.abv.ui.home.activity.OperationListActivity;
import jp.agentec.abook.abv.ui.viewer.activity.DeviceImageListActivity;
import jp.agentec.abook.abv.ui.viewer.activity.HTMLWebViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.HTMLXWalkWebViewActivity;
......@@ -97,7 +98,10 @@ public class ABookPermissionHelper {
// ストレージ
if (ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(mContext, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
if (mContext instanceof HTMLWebViewActivity || mContext instanceof HTMLXWalkWebViewActivity || mContext instanceof OperationListActivity) {
if (mContext instanceof HTMLWebViewActivity ||
mContext instanceof HTMLXWalkWebViewActivity ||
mContext instanceof OperationListActivity ||
mContext instanceof DeviceImageListActivity) {
// リソースパターンの適用
permitionTextResourceId = PatternStringUtil.patternToInt(mContext,
R.string.msg_permission_dialog_storage_album,
......@@ -108,7 +112,6 @@ public class ABookPermissionHelper {
R.string.msg_permission_dialog_storage_update,
getUserPref(mContext, AppDefType.UserPrefKey.RESOURCE_PATTERN_TYPE, 0));
}
}
break;
case Constant.ABookPermissionType.AccessFineLocation:
......
......@@ -78,6 +78,7 @@ import jp.agentec.abook.abv.ui.home.activity.OperationRelatedContentActivity;
import jp.agentec.abook.abv.ui.viewer.activity.AudioPlayActivity;
import jp.agentec.abook.abv.ui.viewer.activity.CheckOZDViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.ContentViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.DeviceImageListActivity;
import jp.agentec.abook.abv.ui.viewer.activity.EnqueteWebViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.HTMLWebViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.HTMLXWalkWebViewActivity;
......@@ -85,6 +86,7 @@ import jp.agentec.abook.abv.ui.viewer.activity.ImageViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.ParentWebViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.PreviewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.VideoViewActivity;
import jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaActivity;
import jp.agentec.abook.abv.ui.viewer.view.OperationTaskLayout;
import jp.agentec.adf.net.http.HttpDownloadSimpleNotification;
import jp.agentec.adf.util.CollectionUtil;
......@@ -1731,4 +1733,15 @@ public class ActivityHandlingHelper extends ABookHelper implements RemoteObserve
public void setPreviousOfSettingActivity(ABVUIActivity activity) {
this.previousOfSettingActivity = activity;
}
/**
* THETAカメラと接続が切れたときにTHETA関連Activityをすべて終了させる
*/
public synchronized void finishAllThetaActivity() {
for (ABVAuthenticatedActivity activity : currentActivityStack) {
if (activity instanceof ThetaActivity) {
activity.finish();
}
}
}
}
package jp.agentec.abook.abv.ui.viewer.activity;
/**
* シーン画像選択画面(タブレット専用)
* 全画面表示ではないダイアログ表示のため、Manifest設定用クラス
*/
public class DeviceImageListActivityDialog extends DeviceImageListActivity {
}
......@@ -657,10 +657,6 @@ public class HTMLWebViewActivity extends ParentWebViewActivity {
return;
}
mUploadMessage.onReceiveValue(result);
} else if (requestCode == ABOOK_CHECK_SELECT_SCENE) {
if (intent != null && result != null) {
confirmEntrySceneDialog(result[0]);
}
}
mUploadMessage = null;
}
......
......@@ -729,10 +729,6 @@ public class HTMLXWalkWebViewActivity extends ParentWebViewActivity {
}
// 動画
mUploadMessage.onReceiveValue(result);
} else if (requestCode == ABOOK_CHECK_SELECT_SCENE) {
if (intent != null && result != null) {
confirmEntrySceneDialog(result);
}
}
mUploadMessage = null;
}
......
package jp.agentec.abook.abv.ui.viewer.activity.theta;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import com.theta.helper.ThetaHelper;
import jp.agentec.abook.abv.bl.common.Constant;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.activity.ABVUIActivity;
import jp.agentec.abook.abv.ui.common.util.AlertDialogUtil;
import jp.agentec.abook.abv.ui.home.helper.ActivityHandlingHelper;
/**
* Theta関連共通クラス
* @version 1.2.300
* @since 2020/06/18
* @author 金鎭星
*/
public class ThetaActivity extends ABVUIActivity {
private static final String TAG = "ThetaActivity";
private WifiManager mWifiManager;
protected ThetaHelper mThetaHelper = new ThetaHelper(this);
private int mWifiScanType;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWifiManager = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}
/**
* Wifiスキャンするブロードキャストリスナークラス
*/
BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
unregisterReceiver(wifiReceiver);
boolean isConnected = mThetaHelper.checkThetaCameraWifiConnected(mWifiManager);
//THETAカメラ画面閉じる
if (mWifiScanType == Constant.WifiScanType.CloseCameraActivity) {
if (isConnected) {
mThetaHelper.disConnectThetaCameraWifi(mWifiManager);
}
mThetaHelper.appConnectedWifiDefault();
finish();
} else if (mWifiScanType == Constant.WifiScanType.ThetaConnectError) { //THETAカメラと通信エラー共通
if (isConnected) {
thetaCameraWifiConnected();
} else {
AlertDialogUtil.showAlertDialog(ThetaActivity.this, R.string.app_name, R.string.msg_theta_wifi_disconnect, true, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
closeProgressPopup();
//Thetaカメラ関連Activity終了
ActivityHandlingHelper.getInstance().finishAllThetaActivity();
mThetaHelper.appConnectedWifiDefault();
}
});
}
}
}
};
/**
* Thetaカメラと通信失敗時、共通メソッド
* @param errorMessageResourceId エラーメッセージリソースID
*/
protected void thetaConnectError(int errorMessageResourceId) {
AlertDialogUtil.showAlertDialog(this, R.string.app_name, errorMessageResourceId, true, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
changeProgressPopup(getString(R.string.progress));
//現在接続状態なのかチェック
registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
mWifiScanType = Constant.WifiScanType.ThetaConnectError;
}
});
}
/**
* THETAカメラ画面から閉じるボタンタップ時にTHETAカメラのWi-Fi機能を無効にするため、
* Wi-Fiが接続状態かチェックする。
*/
protected void closeThetaCameraActivity() {
showProgressPopup();
//現在接続状態なのかチェック
registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
mWifiScanType = Constant.WifiScanType.CloseCameraActivity;
}
/**
* 子クラスで定義
*/
protected void thetaCameraWifiConnected() {}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import com.theta.network.ImageData;
import com.theta.view.ImageListArrayAdapter;
import com.theta.view.ImageRow;
import java.util.List;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.util.AlertDialogUtil;
import jp.agentec.abook.abv.ui.viewer.activity.theta.task.DeleteImageTask;
import jp.agentec.abook.abv.ui.viewer.activity.theta.task.ImageListTask;
import jp.agentec.abook.abv.ui.viewer.activity.theta.task.LoadPhotoTask;
/**
* THETAライブラリ画面
* @version 1.2.300
* @since 2020/05/19
* @author 金鎭星
*/
public class ThetaImageListActivity extends ThetaActivity {
private static final String TAG = "ThetaImageListActivity";
private static int THETA_PREVIEW_BACK_ACTIVITY = 1000;
private ListView mImageListView;
private List<ImageRow> mImageRows;
private int mSelectedPosition;
private boolean isSelected = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ac_theta_image_list);
mImageListView = findViewById(R.id.lv_theta_image);
// 戻るボタン
Button backBtn = findViewById(R.id.btn_back);
backBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
showProgressPopup();
new ImageListTask(this).execute();
}
//端末の戻るボタン禁止
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
Logger.v(TAG, "dispatchKeyEvent %s", event);
if (event.getAction()==KeyEvent.ACTION_UP) { // 戻るボタンを抑止
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
return true;
}
}
return super.dispatchKeyEvent(event);
}
/**
* THETAカメラから全ての画像情報取得するImageListTaskTask終了時に呼ばれる
* @param imageRows 画像データ配列
*/
public void imageListTaskFinish(List<ImageRow> imageRows) {
if (imageRows != null) {
mImageRows = imageRows;
boolean isPhone = false;
if (isNormalSize()) {
isPhone = true;
}
ImageListArrayAdapter imageListArrayAdapter = new ImageListArrayAdapter(ThetaImageListActivity.this, R.layout.listlayout_object, imageRows, isPhone);
mImageListView.setAdapter(imageListArrayAdapter);
mImageListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
final ImageRow selectedItem = (ImageRow) parent.getItemAtPosition(position);
int viewId = view.getId();
if (viewId == R.id.btn_theta_image_save) { //保存ボタン
buttonDoubleTapControl((Button) view);
AlertDialogUtil.showAlertDialog(ThetaImageListActivity.this, R.string.app_name, R.string.msg_theta_image_send_confirm, false, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showProgressPopup(getString(R.string.msg_transferring));
mSelectedPosition = position;
//画像情報を取得
new LoadPhotoTask(ThetaImageListActivity.this, selectedItem.getFileId()).execute();
}
});
} else if (viewId == R.id.btn_theta_image_delete) { //削除ボタン
buttonDoubleTapControl((Button) view);
AlertDialogUtil.showAlertDialog(ThetaImageListActivity.this, R.string.app_name, R.string.msg_theta_image_delete_confirm, false, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showProgressPopup(getString(R.string.msg_deleting));
mSelectedPosition = position;
new DeleteImageTask(ThetaImageListActivity.this).execute(selectedItem.getFileId());
}
});
} else { //通常アイテムタップ時
if (!isSelected) {
isSelected = true;
if (selectedItem.isPhoto()) {
Intent intent = new Intent();
intent.putExtra(ABookKeys.THETA_FILE_ID, selectedItem.getFileId());
intent.putExtra(ABookKeys.THETA_LIST_ACTIVITY_FLG, true);
intent.setClassName(getPackageName(), ThetaImagePreviewActivity.class.getName());
startActivityForResult(intent, THETA_PREVIEW_BACK_ACTIVITY);
} else {
Logger.e(TAG, "is not Photo");
}
//ダブルタップ防止
handler.postDelayed(new Runnable() {
@Override
public void run() {
isSelected = false;
}
}, 1000);
}
}
}
});
closeProgressPopup();
} else {
thetaConnectError(R.string.msg_theta_image_load_fail);
Logger.e(TAG, "failed to get image list");
}
}
/**
* THETAカメラから画像情報取得するLoadPhotoTask終了時に呼ばれる
* 画像データがある場合、ローカルに保存する
* @param imageData 画像データ
*/
public void loadPhotoTaskFinish(ImageData imageData, String fileId) {
if (imageData != null) {
byte[] dataObject = imageData.getRawData();
if (dataObject == null) {
return;
}
Bitmap bitmap = BitmapFactory.decodeByteArray(dataObject, 0, dataObject.length);
if (mThetaHelper.thetaImageLocalSave(bitmap, fileId)) {
showSimpleAlertDialog(R.string.msg_theta_image_send_success);
ImageRow imageRow = mImageRows.get(mSelectedPosition);
imageRow.setIsTransferred(true);
ImageListArrayAdapter imageListArrayAdapter = (ImageListArrayAdapter)mImageListView.getAdapter();
imageListArrayAdapter.setListItem(mImageRows);
imageListArrayAdapter.notifyDataSetChanged();
} else {
Logger.e(TAG,"failed to local save image");
showSimpleAlertDialog(R.string.msg_theta_image_send_fail);
}
closeProgressPopup();
} else {
Logger.e(TAG,"failed loadPhotoTaskFinish");
thetaConnectError(R.string.msg_theta_image_load_fail);
}
}
/**
* THETAカメラから画像を削除するDeleteImageTask終了時に呼ばれる
* @param isSuccess 削除結果(true:成功、false:失敗)
*/
public void deleteImageTaskFinish(boolean isSuccess) {
if (isSuccess) {
AlertDialogUtil.showAlertDialog(ThetaImageListActivity.this, R.string.app_name, R.string.msg_theta_image_delete_success, true, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mImageRows.remove(mSelectedPosition);
ImageListArrayAdapter imageListArrayAdapter = (ImageListArrayAdapter)mImageListView.getAdapter();
imageListArrayAdapter.setListItem(mImageRows);
imageListArrayAdapter.notifyDataSetChanged();
}
});
closeProgressPopup();
} else {
Logger.e(TAG,"failed to delete image");
thetaConnectError(R.string.msg_theta_image_delete_fail);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
//THETAプレビュー画面から転送したあと、戻ったとき再描画を行う。
if (requestCode == THETA_PREVIEW_BACK_ACTIVITY && resultCode == RESULT_OK) {
showProgressPopup();
new ImageListTask(this).execute();
}
}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import com.theta.glview.GLPhotoView;
import com.theta.model.Photo;
import com.theta.model.RotateInertia;
import com.theta.network.ImageData;
import jp.agentec.abook.abv.bl.common.CommonExecutor;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.util.AlertDialogUtil;
import jp.agentec.abook.abv.ui.viewer.activity.theta.task.LoadPhotoTask;
/**
* THETAプレビュー画面
* @version 1.2.300
* @since 2020/05/19
* @author 金鎭星
*/
public class ThetaImagePreviewActivity extends ThetaActivity {
private static final String TAG = "ThetaImagePreviewActivity";
private RotateInertia mRotateInertia = RotateInertia.INERTIA_0;
private Button mSaveBtn;
private GLPhotoView mGLPhotoView;
private Photo mTexture;
private String mFileId;
private boolean isSavedSuccess;
private boolean isThetaListActivityBack;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Logger.d(TAG, "onCreate");
setContentView(R.layout.ac_theta_image_preview);
isSavedSuccess = false;
// 戻るボタン
Button backBtn = findViewById(R.id.btn_back);
backBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//転送後にTHETAライブラリ再描画のため
if (isThetaListActivityBack && isSavedSuccess) {
setResult(RESULT_OK);
}
finish();
}
});
// 転送ボタン
mSaveBtn = findViewById(R.id.btn_theta_image_save);
mSaveBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buttonDoubleTapControl(mSaveBtn);
AlertDialogUtil.showAlertDialog(ThetaImagePreviewActivity.this, R.string.app_name, R.string.msg_theta_image_send_confirm, false, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showProgressPopup();
CommonExecutor.execute(new Runnable() { //スレッド化
@Override
public void run() {
if (mThetaHelper.thetaImageLocalSave(mTexture.getPhoto(), mFileId)) {
showSimpleAlertDialog(R.string.app_name, R.string.msg_theta_image_send_success);
isSavedSuccess = true;
} else {
showSimpleAlertDialog(R.string.app_name, R.string.msg_theta_image_send_fail);
}
closeProgressPopup();
}
});
}
});
}
});
Intent intent = getIntent();
this.mFileId = intent.getStringExtra(ABookKeys.THETA_FILE_ID);
this.isThetaListActivityBack = intent.getBooleanExtra(ABookKeys.THETA_LIST_ACTIVITY_FLG, false);
mGLPhotoView = findViewById(R.id.photo_image);
mGLPhotoView.setmRotateInertia(mRotateInertia);
new LoadPhotoTask(this, mFileId).execute();
}
//端末の戻るボタン禁止
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
Logger.v(TAG, "dispatchKeyEvent %s", event);
if (event.getAction()==KeyEvent.ACTION_UP) { // 戻るボタンを抑止
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
return true;
}
}
return super.dispatchKeyEvent(event);
}
/**
* THETAカメラから画像情報取得するLoadPhotoTask終了時に呼ばれる
* @param imageData 画像データ
*/
public void loadPhotoTaskFinish(ImageData imageData) {
if (imageData != null) {
byte[] dataObject = imageData.getRawData();
if (dataObject == null) {
return;
}
Bitmap __bitmap = BitmapFactory.decodeByteArray(dataObject, 0, dataObject.length);
Double yaw = imageData.getYaw();
Double pitch = imageData.getPitch();
Double roll = imageData.getRoll();
mTexture = new Photo(__bitmap, yaw, pitch, roll);
if (null != mGLPhotoView) {
mGLPhotoView.setTexture(mTexture);
}
closeProgressPopup();
} else {
thetaConnectError(R.string.msg_theta_image_load_fail);
Logger.e(TAG,"failed loadPhotoTaskFinish");
}
}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta.task;
import android.os.AsyncTask;
import com.theta.network.HttpConnector;
import com.theta.network.HttpEventListener;
import java.lang.ref.WeakReference;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.constant.ABookValues;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaImageListActivity;
/**
* THETAカメラから1つの画像を削除するスレッド
* @version 1.2.300
* @author kimjinsung
* @since 2020/05/29
*/
public class DeleteImageTask extends AsyncTask<String, String, Void> {
private static final String TAG = "DeleteImageTask";
private final WeakReference<ThetaImageListActivity> refActivity;
public DeleteImageTask(ThetaImageListActivity refActivity) {
this.refActivity = new WeakReference<>(refActivity);
}
@Override
protected Void doInBackground(String... fileId) {
Logger.d(TAG, "doInBackground delete " + fileId[0]);
DeleteEventListener deleteListener = new DeleteEventListener();
boolean isOldApi = PreferenceUtil.getUserPref(refActivity.get(),ABookKeys.THETA_OLD_VERSION_FLG, false);
HttpConnector camera = new HttpConnector(ABookValues.THETA_IP_ADDRESS, isOldApi);
camera.deleteFile(fileId[0], deleteListener);
return null;
}
private class DeleteEventListener implements HttpEventListener {
@Override
public void onCheckStatus(boolean newStatus) {
if (newStatus) {
Logger.d(TAG, "onCheckStatus deleteFile:FINISHED");
} else {
Logger.d(TAG,"onCheckStatus deleteFile:IN PROGRESS");
}
}
@Override
public void onObjectChanged(String latestCapturedFileId) {
Logger.d(TAG, "onObjectChanged delete " + latestCapturedFileId);
}
@Override
public void onCompleted() {
Logger.d(TAG, "onCompleted deleted.");
refActivity.get().runOnUiThread(new Runnable() {
@Override
public void run() {
ThetaImageListActivity imageListActivity = refActivity.get();
imageListActivity.deleteImageTaskFinish(true);
}
});
}
@Override
public void onError(String errorMessage) {
Logger.e(TAG, "delete error " + errorMessage);
refActivity.get().runOnUiThread(new Runnable() {
@Override
public void run() {
ThetaImageListActivity imageListActivity = refActivity.get();
imageListActivity.deleteImageTaskFinish(false);
}
});
}
}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta.task;
import android.os.AsyncTask;
import com.theta.helper.ThetaHelper;
import com.theta.network.HttpConnector;
import com.theta.network.ThetaDeviceInfo;
import java.lang.ref.WeakReference;
import jp.agentec.abook.abv.bl.common.constant.ABookValues;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.ui.viewer.activity.DeviceImageListActivity;
/**
* THETAカメラ情報を取得するスレッド
* @version 1.2.300
* @author kimjinsung
* @since 2020/05/29
*/
public class DeviceInfoTask extends AsyncTask<Void, String, ThetaDeviceInfo> {
private static final String TAG = "DeviceInfoTask";
private final WeakReference<DeviceImageListActivity> refActivity;
private static final int FAIL_RETRAY_DELAY_MILLIS = 2000;
public DeviceInfoTask(DeviceImageListActivity refActivity) {
this.refActivity = new WeakReference<>(refActivity);
}
@Override
protected ThetaDeviceInfo doInBackground(Void... params) {
Logger.d(TAG, "doInBackground");
HttpConnector camera = new HttpConnector(ABookValues.THETA_IP_ADDRESS);
final int MAX_RETRY_COUNT = 6;
ThetaDeviceInfo deviceInfo = null;
//Wifi切り替え時間が必要なので、失敗した場合、5回リトライする。
for (int retryCount = 0; retryCount < MAX_RETRY_COUNT; retryCount++) {
deviceInfo = camera.getDeviceInfo();
if (deviceInfo.getModel() == null || deviceInfo.getModel().length() == 0) {
try {
Thread.sleep(FAIL_RETRAY_DELAY_MILLIS);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if (retryCount == 0) { //失敗時、LTE環境の影響のため、アプリで利用するネットワークを設定
ThetaHelper helper = new ThetaHelper(refActivity.get());
helper.appConnectedWifiOnly();
}
} else {
retryCount = MAX_RETRY_COUNT;
}
}
return deviceInfo;
}
@Override
protected void onPostExecute(ThetaDeviceInfo deviceInfo) {
Logger.d(TAG, "onPostExecute");
DeviceImageListActivity activity = refActivity.get();
activity.thetaDeviceInfoTaskFinish(deviceInfo);
}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta.task;
import android.os.AsyncTask;
import com.theta.network.HttpConnector;
import java.lang.ref.WeakReference;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.constant.ABookValues;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaCameraActivity;
/**
* THETAカメラのWifi機能をOFFにするスレッド
* @version 1.2.300
* @author kimjinsung
* @since 2020/05/29
*/
public class FinishWlanTask extends AsyncTask<Void, String, String> {
private static final String TAG = "FinishWlanTask";
private static final int SLEEP_TIME = 2000;
private final WeakReference<ThetaCameraActivity> refActivity;
public FinishWlanTask(ThetaCameraActivity refActivity) {
this.refActivity = new WeakReference<>(refActivity);
}
@Override
protected String doInBackground(Void... params) {
Logger.d(TAG, "doInBackground");
boolean isOldApi = PreferenceUtil.getUserPref(refActivity.get(), ABookKeys.THETA_OLD_VERSION_FLG, false);
HttpConnector camera = new HttpConnector(ABookValues.THETA_IP_ADDRESS, isOldApi);
if (camera.cameraFinishWlan()) {
try {
// Wifi切り替える時間2秒スリップ
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
Logger.e(TAG, "sleep error" + e.toString());
}
return ABookValues.SUCCESS;
}
return ABookValues.FAIL;
}
@Override
protected void onPostExecute(String result) {
Logger.d(TAG, "onPostExecute");
ThetaCameraActivity activity = refActivity.get();
activity.finishWlanTaskFinish(result);
}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta.task;
import android.os.AsyncTask;
import com.theta.network.HttpConnector;
import java.lang.ref.WeakReference;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.constant.ABookValues;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaCameraActivity;
/**
* THETAカメラの露出情報を取得するスレッド
* @version 1.2.300
* @author kimjinsung
* @since 2020/05/29
*/
public class GetOptionExposureTask extends AsyncTask<Void, String, String> {
private static final String TAG = "GetOptionExposureTask";
private final WeakReference<ThetaCameraActivity> refActivity;
public GetOptionExposureTask(ThetaCameraActivity refActivity) {
this.refActivity = new WeakReference<>(refActivity);
}
@Override
protected String doInBackground(Void... params) {
Logger.d(TAG, "doInBackground");
boolean isOldApi = PreferenceUtil.getUserPref(refActivity.get(), ABookKeys.THETA_OLD_VERSION_FLG, false);
HttpConnector camera = new HttpConnector(ABookValues.THETA_IP_ADDRESS, isOldApi);
return camera.getOptionExposure();
}
@Override
protected void onPostExecute(String exposure) {
Logger.d(TAG, "onPostExecute");
ThetaCameraActivity activity = refActivity.get();
activity.getOptionExposureTaskFinish(exposure);
}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta.task;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.util.Log;
import com.theta.helper.ThetaHelper;
import com.theta.network.HttpConnector;
import com.theta.network.ImageInfo;
import com.theta.view.ImageRow;
import java.io.ByteArrayOutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.constant.ABookValues;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaImageListActivity;
/**
* THETAカメラ内の画像情報取得スレッド
* @version 1.2.300
* @author kimjinsung
* @since 2020/05/29
*/
public class ImageListTask extends AsyncTask<Void, String, List<ImageRow>> {
private static final String TAG = "ImageListTask";
private final WeakReference<ThetaImageListActivity> refActivity;
public ImageListTask(ThetaImageListActivity refActivity) {
this.refActivity = new WeakReference<>(refActivity);
}
@Override
protected void onPreExecute() {
Logger.d(TAG, "onPreExecute");
}
@Override
protected List<ImageRow> doInBackground(Void... params) {
try {
Logger.d(TAG, "doInBackground");
boolean isOldApi = PreferenceUtil.getUserPref(refActivity.get(), ABookKeys.THETA_OLD_VERSION_FLG, false);
HttpConnector camera = new HttpConnector(ABookValues.THETA_IP_ADDRESS, isOldApi);
ArrayList<ImageInfo> objects = camera.getList();
if (objects == null) { //エラー発生
return null;
}
List<ImageRow> imageRows = new ArrayList<>();
int objectSize = objects.size();
ThetaHelper thetaHelper = new ThetaHelper(refActivity.get());
for (int i = 0; i < objectSize; i++) {
ImageInfo object = objects.get(i);
//動画ファイルは除外
if (object.getFileFormat().equals(ImageInfo.FILE_FORMAT_CODE_EXIF_MPEG)) {
continue;
}
ImageRow imageRow = new ImageRow();
imageRow.setFileId(object.getFileId());
imageRow.setFileSize(object.getFileSize());
imageRow.setFileName(object.getFileName());
imageRow.setCaptureDate(object.getCaptureDate());
imageRow.setIsPhoto(true);
Bitmap thumbnail = camera.getThumb(object.getFileId());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, baos);
final byte[] thumbnailImage = baos.toByteArray();
imageRow.setThumbnail(thumbnailImage);
if (thetaHelper.transferredImage(object.getFileId())) {
imageRow.setIsTransferred(true);
} else {
imageRow.setIsTransferred(false);
}
imageRows.add(imageRow);
}
return imageRows;
} catch (Throwable throwable) {
String errorLog = Log.getStackTraceString(throwable);
Logger.e(errorLog);
return null;
}
}
@Override
protected void onProgressUpdate(String... values) {
for (String log : values) {
Logger.d(TAG, "onProgressUpdate" + log);
}
}
@Override
protected void onPostExecute(List<ImageRow> imageRows) {
Logger.d(TAG, "onPostExecute");
ThetaImageListActivity activity = refActivity.get();
activity.imageListTaskFinish(imageRows);
}
@Override
protected void onCancelled() {
Logger.e(TAG, "onCancelled");
ThetaImageListActivity activity = refActivity.get();
activity.imageListTaskFinish(null);
}
}
package jp.agentec.abook.abv.ui.viewer.activity.theta.task;
import android.app.Activity;
import android.os.AsyncTask;
import android.util.Log;
import com.theta.network.HttpConnector;
import com.theta.network.HttpDownloadListener;
import com.theta.network.ImageData;
import java.lang.ref.WeakReference;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
import jp.agentec.abook.abv.bl.common.constant.ABookValues;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.cl.util.PreferenceUtil;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaImageListActivity;
import jp.agentec.abook.abv.ui.viewer.activity.theta.ThetaImagePreviewActivity;
/**
* THETAカメラ内の1つの画像情報を取得スレッド
* @version 1.2.300
* @author kimjinsung
* @since 2020/05/29
*/
public class LoadPhotoTask extends AsyncTask<Void, Object, ImageData> {
private static final String TAG = "LoadPhotoTask";
private final WeakReference<Activity> refActivity;
private String mFileId;
private long fileSize;
private long receivedDataSize = 0;
public LoadPhotoTask(Activity refActivity, String fileId) {
this.refActivity = new WeakReference<>(refActivity);
this.mFileId = fileId;
}
@Override
protected void onPreExecute() {
Logger.d(TAG, "onPreExecute");
Activity activity = refActivity.get();
if (activity instanceof ThetaImagePreviewActivity) {
ThetaImagePreviewActivity previewActivity = (ThetaImagePreviewActivity)activity;
previewActivity.showProgressView(activity.getString(R.string.progress));
}
}
@Override
protected ImageData doInBackground(Void... params) {
try {
Logger.d(TAG,"start to download image" + mFileId);
boolean isOldApi = PreferenceUtil.getUserPref(refActivity.get(), ABookKeys.THETA_OLD_VERSION_FLG, false);
HttpConnector camera = new HttpConnector(ABookValues.THETA_IP_ADDRESS, isOldApi);
ImageData resizedImageData = camera.getImage(mFileId, new HttpDownloadListener() {
@Override
public void onTotalSize(long totalSize) {
fileSize = totalSize;
}
@Override
public void onDataReceived(int size) {
receivedDataSize += size;
if (fileSize != 0) {
int progressPercentage = (int) (receivedDataSize * 100 / fileSize);
publishProgress(progressPercentage);
}
}
});
return resizedImageData;
} catch (Throwable throwable) {
String errorLog = Log.getStackTraceString(throwable);
Logger.e(errorLog);
return null;
}
}
@Override
protected void onProgressUpdate(Object... values) {
Activity activity = refActivity.get();
if (activity instanceof ThetaImagePreviewActivity) {
ThetaImagePreviewActivity previewActivity = (ThetaImagePreviewActivity)activity;
for (Object param : values) {
if (param instanceof Integer) {
Logger.d(TAG, "onProgressUpdate progress = " + param);
previewActivity.progressDialogHorizontal.setProgress((Integer) param);
} else if (param instanceof String) {
Logger.d(TAG, "onProgressUpdate param = " + param);
}
}
}
}
@Override
protected void onPostExecute(ImageData imageData) {
Logger.d(TAG, "onPostExecute");
Activity activity = refActivity.get();
if (activity instanceof ThetaImagePreviewActivity) {
ThetaImagePreviewActivity previewActivity = (ThetaImagePreviewActivity)activity;
previewActivity.loadPhotoTaskFinish(imageData);
} else if (activity instanceof ThetaImageListActivity) {
ThetaImageListActivity imageListActivity = (ThetaImageListActivity)activity;
imageListActivity.loadPhotoTaskFinish(imageData, mFileId);
}
}
}
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