OSDN Git Service

Android11対応に向けて修正を開始。
authorMRSa <mrsa@myad.jp>
Sun, 20 Sep 2020 13:41:29 +0000 (22:41 +0900)
committerMRSa <mrsa@myad.jp>
Sun, 20 Sep 2020 13:41:29 +0000 (22:41 +0900)
14 files changed:
.idea/codeStyles/Project.xml
.idea/jarRepositories.xml
app/build.gradle
app/src/main/java/net/osdn/gokigen/a01d/camera/kodak/wrapper/KodakInterfaceProvider.java
app/src/main/java/net/osdn/gokigen/a01d/camera/kodak/wrapper/connection/KodakCameraConnectSequence.java
app/src/main/java/net/osdn/gokigen/a01d/liveview/CameraLiveImageView.java
app/src/main/java/net/osdn/gokigen/a01d/liveview/StoreImage.kt [new file with mode: 0644]
app/src/main/java/net/osdn/gokigen/a01d/liveview/StoreImageOld.java [moved from app/src/main/java/net/osdn/gokigen/a01d/liveview/StoreImage.java with 97% similarity]
app/src/main/java/net/osdn/gokigen/a01d/preference/IPreferencePropertyAccessor.java
app/src/main/java/net/osdn/gokigen/a01d/preference/summary/PreferenceFragmentSummary.java
app/src/main/res/values-ja/strings.xml
app/src/main/res/values/strings.xml
app/src/main/res/xml/preferences_summary.xml
build.gradle

index 681f41a..0d15693 100644 (file)
@@ -1,5 +1,23 @@
 <component name="ProjectCodeStyleConfiguration">
   <code_scheme name="Project" version="173">
+    <JetCodeStyleSettings>
+      <option name="PACKAGES_TO_USE_STAR_IMPORTS">
+        <value>
+          <package name="java.util" alias="false" withSubpackages="false" />
+          <package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
+          <package name="io.ktor" alias="false" withSubpackages="true" />
+        </value>
+      </option>
+      <option name="PACKAGES_IMPORT_LAYOUT">
+        <value>
+          <package name="" alias="false" withSubpackages="true" />
+          <package name="java" alias="false" withSubpackages="true" />
+          <package name="javax" alias="false" withSubpackages="true" />
+          <package name="kotlin" alias="false" withSubpackages="true" />
+          <package name="" alias="true" withSubpackages="true" />
+        </value>
+      </option>
+    </JetCodeStyleSettings>
     <codeStyleSettings language="XML">
       <indentOptions>
         <option name="CONTINUATION_INDENT_SIZE" value="4" />
index f406759..2b47597 100644 (file)
       <option name="name" value="maven" />
       <option name="url" value="https://maven.google.com" />
     </remote-repository>
+    <remote-repository>
+      <option name="id" value="MavenRepo" />
+      <option name="name" value="MavenRepo" />
+      <option name="url" value="https://repo.maven.apache.org/maven2/" />
+    </remote-repository>
   </component>
 </project>
\ No newline at end of file
index 6fe00ac..85b4471 100644 (file)
@@ -1,4 +1,5 @@
 apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
 
 android {
     compileSdkVersion 29
@@ -6,8 +7,8 @@ android {
         applicationId "net.osdn.gokigen.a01d"
         minSdkVersion 14
         targetSdkVersion 29
-        versionCode 10901
-        versionName "1.9.1"
+        versionCode 10902
+        versionName "1.9.2"
     }
     buildTypes {
         release {
@@ -20,11 +21,16 @@ android {
 dependencies {
     api fileTree(dir: 'libs', include: ['*.jar'])
     implementation 'androidx.appcompat:appcompat:1.2.0'
-    implementation 'androidx.exifinterface:exifinterface:1.2.0'
+    implementation 'androidx.exifinterface:exifinterface:1.3.0'
     implementation 'androidx.preference:preference:1.1.1'
-    implementation 'com.google.android.material:material:1.2.0'
-    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+    implementation 'com.google.android.material:material:1.2.1'
+    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
     implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
 
     api files('libs/olycamerakit.jar')
+    implementation "androidx.core:core-ktx:1.3.1"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
+repositories {
+    mavenCentral()
 }
index 1d2a8ea..ec76c0f 100644 (file)
@@ -54,7 +54,7 @@ public class KodakInterfaceProvider implements IKodakInterfaceProvider, IDisplay
     private final KodakCameraInformation cameraInformation;
     private KodakCaptureControl captureControl;
     private KodakFocusingControl focusingControl;
-    private KodakConnection canonConnection;
+    private KodakConnection kodakConnection;
     private KodakCommandCommunicator commandPublisher;
     private KodakLiveViewControl liveViewControl;
     private KodakZoomLensControl zoomControl;
@@ -88,7 +88,7 @@ public class KodakInterfaceProvider implements IKodakInterfaceProvider, IDisplay
         commandPublisher = new KodakCommandCommunicator(this, ipAddress, controlPort, true, false);
         liveViewControl = new KodakLiveViewControl(context, ipAddress, liveviewPort);
         statusChecker = new KodakStatusChecker();
-        canonConnection = new KodakConnection(context, provider, this, statusChecker);
+        kodakConnection = new KodakConnection(context, provider, this, statusChecker);
         cameraInformation = new KodakCameraInformation();
         zoomControl = new KodakZoomLensControl(commandPublisher);
         this.statusListener = statusListener;
@@ -122,7 +122,7 @@ public class KodakInterfaceProvider implements IKodakInterfaceProvider, IDisplay
     @Override
     public ICameraConnection getCameraConnection()
     {
-        return (canonConnection);
+        return (kodakConnection);
     }
 
     @Override
index f91cf70..d1feae2 100644 (file)
@@ -134,10 +134,12 @@ public class KodakCameraConnectSequence implements Runnable, IKodakCommandCallba
                 break;
             case SEQ_CONNECT_04:
                 interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.kodak_connect_connecting4), false, false, 0);
+                // ここで、パスワードの Base64情報を切り出す(FC 03 の応答、 0x0058 ~ 64バイトの文字列を切り出して、Base64エンコードする)
                 commandIssuer.enqueueCommand(new KodakConnectSequence05(this));
                 break;
             case SEQ_CONNECT_05:
                 interfaceProvider.getInformationReceiver().updateMessage(context.getString(R.string.kodak_connect_connecting5), false, false, 0);
+                // ここで、パスワードの情報を切り出す (FE 03 の応答、 0x0078 ~ 文字列を切り出す。)
                 commandIssuer.enqueueCommand(new KodakConnectSequence06(this));
                 break;
             case SEQ_CONNECT_06:
index 3147448..46afdd0 100644 (file)
@@ -104,7 +104,7 @@ public class CameraLiveImageView extends View implements IImageDataReceiver, IAu
     private void initComponent(Context context)
     {
         prepareFile();
-        storeImage = new StoreImage(context);
+        storeImage = new StoreImage(context, false);
         ShowMessageHolder messageHolder =  new ShowMessageHolder();
         this.messageHolder = messageHolder;
         messageDrawer = messageHolder;
diff --git a/app/src/main/java/net/osdn/gokigen/a01d/liveview/StoreImage.kt b/app/src/main/java/net/osdn/gokigen/a01d/liveview/StoreImage.kt
new file mode 100644 (file)
index 0000000..60d87c3
--- /dev/null
@@ -0,0 +1,180 @@
+package net.osdn.gokigen.a01d.liveview
+import android.content.ContentValues
+import android.content.Context
+import android.database.DatabaseUtils
+import android.graphics.Bitmap
+import android.net.Uri
+import android.os.Build
+import android.os.Environment
+import android.provider.MediaStore
+import android.util.Log
+import androidx.preference.PreferenceManager
+import net.osdn.gokigen.a01d.R
+import net.osdn.gokigen.a01d.preference.IPreferencePropertyAccessor
+import java.io.File
+import java.io.FileOutputStream
+import java.text.SimpleDateFormat
+import java.util.*
+
+class StoreImage(private val context: Context, private val dumpLog : Boolean = false) : IStoreImage
+{
+    private val TAG = toString()
+    private val FILENAME_FORMAT = "yyyyMMdd_HHmmss"
+
+    override fun doStore(bitmapToStore: Bitmap)
+    {
+        try
+        {
+            // 保存処理(プログレスダイアログ(「保存中...」)を表示
+
+            val preference = PreferenceManager.getDefaultSharedPreferences(context)
+            val isLocalLocation  = preference.getBoolean(
+                IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION,
+                IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION_DEFAULT_VALUE
+            )
+            if (isLocalLocation)
+            {
+                saveImageLocal(bitmapToStore)
+            }
+            else
+            {
+                saveImageExternal(bitmapToStore)
+            }
+
+            // 保存処理(プログレスダイアログ(「保存中...」)を削除
+        }
+        catch (t: Throwable)
+        {
+            t.printStackTrace()
+        }
+    }
+
+    private fun prepareLocalOutputDirectory(): File
+    {
+        val mediaDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
+        mediaDir?.mkdirs()
+        return (if (mediaDir != null && mediaDir.exists()) mediaDir else context.filesDir)
+    }
+
+    /**
+     * ビットマップイメージをファイルに出力する
+     *
+     * @param targetImage  出力するビットマップイメージ
+     */
+    private fun saveImageLocal(targetImage: Bitmap)
+    {
+        try
+        {
+            val fileName = "L" + SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis()) + ".jpg"
+            val photoFile = File(prepareLocalOutputDirectory(), fileName)
+            val outputStream = FileOutputStream(photoFile)
+            targetImage.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
+            outputStream.flush()
+            outputStream.close()
+        }
+        catch (t: Throwable)
+        {
+            t.printStackTrace()
+        }
+    }
+
+    @Suppress("DEPRECATION")
+    private fun getExternalOutputDirectory(): File
+    {
+        val directoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).path + "/" + context.getString(R.string.app_name2) + "/"
+        val target = File(directoryPath)
+        try
+        {
+            target.mkdirs()
+        }
+        catch (e: Exception)
+        {
+            e.printStackTrace()
+        }
+        if (dumpLog)
+        {
+            Log.v(TAG, "  ----- RECORD Directory PATH : $directoryPath -----")
+        }
+        return (target)
+    }
+
+    /**
+     * ビットマップイメージを外部ストレージのファイルに出力する
+     *
+     * @param targetImage  出力するビットマップイメージ
+     */
+    @Suppress("DEPRECATION")
+    private fun saveImageExternal(targetImage: Bitmap)
+    {
+        try
+        {
+            if (!isExternalStorageWritable())
+            {
+                saveImageLocal(targetImage)
+                return
+            }
+
+            val outputDir = getExternalOutputDirectory()
+            val resolver = context.contentResolver
+            val mimeType = "image/jpeg"
+            //val now = System.currentTimeMillis()
+            val path = Environment.DIRECTORY_DCIM + File.separator + context.getString(R.string.app_name2)
+            val fileName = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(Calendar.getInstance().time) + ".jpg"
+
+            val extStorageUri : Uri
+            val values = ContentValues()
+            values.put(MediaStore.Images.Media.TITLE, fileName)
+            values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
+            values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+            {
+                values.put(MediaStore.Images.Media.RELATIVE_PATH, path)
+                values.put(MediaStore.Images.Media.IS_PENDING, true)
+                extStorageUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
+            }
+            else
+            {
+                values.put(MediaStore.Images.Media.DATA, outputDir.absolutePath + File.separator + fileName)
+                extStorageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+            }
+            val imageUri = resolver.insert(extStorageUri, values)
+            if (imageUri != null)
+            {
+                resolver.update(imageUri, values, null, null)
+
+                ////////////////////////////////////////////////////////////////
+                if (dumpLog)
+                {
+                    val cursor = resolver.query(imageUri, null, null, null, null)
+                    DatabaseUtils.dumpCursor(cursor)
+                    cursor!!.close()
+                }
+                ////////////////////////////////////////////////////////////////
+
+                val outputStream = resolver.openOutputStream(imageUri)
+                if (outputStream != null)
+                {
+                    targetImage.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
+                    outputStream.flush()
+                    outputStream.close()
+                }
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+                {
+                    values.put(MediaStore.Images.Media.IS_PENDING, false)
+                    resolver.update(imageUri, values, null, null)
+
+                }
+            }
+        }
+        catch (t: Throwable)
+        {
+            t.printStackTrace()
+        }
+    }
+
+    private fun isExternalStorageWritable(): Boolean
+    {
+        return (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED)
+    }
+
+}
@@ -22,12 +22,12 @@ import java.util.Locale;
  *   画像の保管クラス
  *
  */
-class StoreImage implements IStoreImage
+class StoreImageOld implements IStoreImage
 {
     private final String TAG = toString();
     private final Context context;
 
-    StoreImage(Context context)
+    StoreImageOld(Context context)
     {
         this.context = context;
     }
index fd1dbf7..2d04aa8 100644 (file)
@@ -114,6 +114,8 @@ public interface IPreferencePropertyAccessor
     String KODAK_LIVEVIEW_PORT = "kodak_liveview_port";
     String KODAK_LIVEVIEW_PORT_DEFAULT_VALUE = "9176";
 
+    String SAVE_LOCAL_LOCATION = "save_local_location";
+    boolean SAVE_LOCAL_LOCATION_DEFAULT_VALUE = false;
  /*
     int CHOICE_SPLASH_SCREEN = 10;
 
index 1034755..4cae5a3 100644 (file)
@@ -154,6 +154,10 @@ public class PreferenceFragmentSummary extends PreferenceFragmentCompat implemen
             {
                 editor.putString(IPreferencePropertyAccessor.KODAK_FLASH_MODE, IPreferencePropertyAccessor.KODAK_FLASH_MODE_DEFAULT_VALUE);
             }
+            if (!items.containsKey(IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION))
+            {
+                editor.putBoolean(IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION, IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION_DEFAULT_VALUE);
+            }
             editor.apply();
         }
         catch (Exception e)
@@ -195,6 +199,11 @@ public class PreferenceFragmentSummary extends PreferenceFragmentCompat implemen
                     Log.v(TAG, " " + key + "  , " + value);
                     break;
 
+                case IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION:
+                    value = preferences.getBoolean(key, IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION_DEFAULT_VALUE);
+                    Log.v(TAG, " " + key + "  , " + value);
+                    break;
+
                 default:
                     String strValue = preferences.getString(key, "");
                     setListPreference(key, key, strValue);
@@ -419,6 +428,7 @@ public class PreferenceFragmentSummary extends PreferenceFragmentCompat implemen
                         setBooleanPreference(IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, IPreferencePropertyAccessor.CAPTURE_BOTH_CAMERA_AND_LIVE_VIEW, defaultValue);
                         setBooleanPreference(IPreferencePropertyAccessor.CAPTURE_ONLY_LIVE_VIEW, IPreferencePropertyAccessor.CAPTURE_ONLY_LIVE_VIEW, false);
                         setBooleanPreference(IPreferencePropertyAccessor.CACHE_LIVEVIEW_PICTURES, IPreferencePropertyAccessor.CACHE_LIVEVIEW_PICTURES, false);
+                        setBooleanPreference(IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION, IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION, IPreferencePropertyAccessor.SAVE_LOCAL_LOCATION_DEFAULT_VALUE);
                     }
                     catch (Exception e)
                     {
index 145e0f7..403e6e2 100644 (file)
     <string name="pref_kodak_liveview_port">カメラライブビューポート番号</string>
     <string name="pref_summary_kodak_liveview_port">通常、変更は不要です (初期値:9176)</string>
 
+    <string name="pref_save_local_location">ライブビュー画像をアプリ固有領域に保存</string>
+    <string name="pref_summary_save_local_location">ライブビューイメージの保存先をアプリ固有領域にします。</string>
+
 </resources>
index 1cafe1c..ba379f0 100644 (file)
     <string name="pref_kodak_liveview_port">Camera Liveview Port</string>
     <string name="pref_summary_kodak_liveview_port">default: 9176 </string>
 
+    <string name="pref_save_local_location">Save local location(Liveview Image)</string>
+    <string name="pref_summary_save_local_location">The liveview image saves in application local location.</string>
+
 </resources>
index 82d6d2d..8c139e9 100644 (file)
             android:summary="@string/pref_summary_capture_only_live_view" />
 
         <CheckBoxPreference
+            android:key="save_local_location"
+            android:title="@string/pref_save_local_location"
+            android:summary="@string/pref_summary_save_local_location"/>
+
+        <CheckBoxPreference
             android:key="cache_liveview_pictures"
             android:title="@string/pref_cache_liveview_pictures"
             android:summary="@string/pref_summary_cache_liveview_pictures" />
index 3824f76..50d3579 100644 (file)
@@ -1,12 +1,14 @@
 // Top-level build file where you can add configuration options common to all sub-projects/modules.
 
 buildscript {
+    ext.kotlin_version = '1.4.10'
     repositories {
         jcenter()
         google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:4.0.0'
+        classpath 'com.android.tools.build:gradle:4.0.1'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files