From 6aef2feab7cefe3f5282536bc2c74d2c40fbf897 Mon Sep 17 00:00:00 2001 From: TakayukiHoshi1984 Date: Fri, 19 Feb 2021 16:02:36 +0900 Subject: [PATCH 1/2] =?UTF-8?q?Android11=E4=BB=A5=E9=99=8D=E3=81=AE?= =?UTF-8?q?=E8=A8=BC=E6=98=8E=E6=9B=B8=E3=82=A4=E3=83=B3=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=BC=E3=83=AB=E6=96=B9=E6=B3=95=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 更新内容 * Android11からはアプリからルート証明書を自動的にインストールできなくなった。 * 外部ストレージのDonwloadディレクトリにルート証明書を保存する。 * 設定画面から手動でルート証明書をインストールする手順を表示するようにした。 --- .../src/main/AndroidManifest.xml | 8 +- .../android/manager/DConnectService.java | 48 ++++++- .../SecuritySettingDialogActivity.java | 41 ++++++ .../SecuritySettingDialogFragment.java | 131 ++++++++++++++++++ .../src/main/res/values-ja/strings.xml | 6 + .../src/main/res/values/strings.xml | 7 + 6 files changed, 234 insertions(+), 7 deletions(-) create mode 100644 dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogActivity.java create mode 100755 dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java diff --git a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/AndroidManifest.xml b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/AndroidManifest.xml index 92b80899a1..65bdb542ab 100755 --- a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/AndroidManifest.xml +++ b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/AndroidManifest.xml @@ -127,7 +127,13 @@ android:label="@string/app_name" android:theme="@style/AppTheme.AppCompat.Translucent"> - + + + = Build.VERSION_CODES.R) { + Intent installIntent = new Intent(); + installIntent.setClass(getApplicationContext(), SecuritySettingDialogActivity.class); + installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + installIntent.putExtra(SecuritySettingDialogFragment.EXTRA_ROOT_CERT, rootCert.getEncoded()); + startActivity(installIntent); + } else { + Intent installIntent = KeyChain.createInstallIntent(); + installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + installIntent.putExtra(KeyChain.EXTRA_NAME, "Device Connect Root CA"); + installIntent.putExtra(KeyChain.EXTRA_CERTIFICATE, rootCert.getEncoded()); + startActivity(installIntent); + } } catch (Exception e) { mLogger.log(Level.SEVERE, "Failed to encode server certificate.", e); } diff --git a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogActivity.java b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogActivity.java new file mode 100644 index 0000000000..1e808212e7 --- /dev/null +++ b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogActivity.java @@ -0,0 +1,41 @@ +/* + SecuritySettingDialogActivity.java + Copyright (c) 2021 NTT DOCOMO,INC. + Released under the MIT license + http://opensource.org/licenses/mit-license.php + */ +package org.deviceconnect.android.manager.setting; + +import android.content.Intent; +import android.os.Bundle; + +import androidx.fragment.app.FragmentActivity; + +/** + * セキュリティの設定画面を出すダイアログ表示用Activity. + * @author NTT DOCOMO, INC. + */ +public class SecuritySettingDialogActivity extends FragmentActivity { + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (intent == null) { + finish(); + return; + } + + byte[] rootCert = intent.getByteArrayExtra(SecuritySettingDialogFragment.EXTRA_ROOT_CERT); + if (rootCert == null) { + finish(); + return; + } + + SecuritySettingDialogFragment fragment = new SecuritySettingDialogFragment(); + Bundle args = new Bundle(); + args.putByteArray(SecuritySettingDialogFragment.EXTRA_ROOT_CERT, rootCert); + fragment.setArguments(args); + fragment.show(getSupportFragmentManager(), "security_setting_dialog"); + } +} diff --git a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java new file mode 100755 index 0000000000..a66eeb7c26 --- /dev/null +++ b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java @@ -0,0 +1,131 @@ +/* + SecuritySettingDialogFragment.java + Copyright (c) 2021 NTT DOCOMO,INC. + Released under the MIT license + http://opensource.org/licenses/mit-license.php + */ +package org.deviceconnect.android.manager.setting; + +import android.app.Activity; +import android.app.Dialog; +import android.app.SearchManager; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.provider.Settings; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; + +import org.deviceconnect.android.deviceplugin.host.file.HostFileProvider; +import org.deviceconnect.android.manager.R; +import org.deviceconnect.android.provider.FileManager; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * セキュリティ設定画面を開くダイアログ. + * + * @author NTT DOCOMO, INC. + */ +public class SecuritySettingDialogFragment extends DialogFragment { + private static final String TAG = "SecuritySettingDialogFragment"; + public static final String EXTRA_ROOT_CERT = "root_cert"; + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + Bundle args = getArguments(); + if (args == null) { + dismiss(); + } + byte[] rootCert = getArguments().getByteArray(EXTRA_ROOT_CERT); + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(getString(R.string.dialog_title_security_setting)); + builder.setMessage(getString(R.string.dialog_message_security_setting)); + builder.setPositiveButton(R.string.dialog_open_security_setting, (dialog, which) -> { + final FileManager fileMgr = new FileManager(getContext(), HostFileProvider.class.getName()); + fileMgr.saveFile("manager.pem", rootCert, true, new FileManager.SaveFileCallback() { + @Override + public void onSuccess(@NonNull String s) { + shareCA(new File(fileMgr.getBasePath(), "manager.pem")); + Intent installIntent = new Intent(Settings.ACTION_APP_SEARCH_SETTINGS); + installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + installIntent.putExtra(SearchManager.QUERY, "CA証明書"); + startActivity(installIntent); + } + + @Override + public void onFail(@NonNull Throwable throwable) { + Toast.makeText(getContext(), R.string.dialog_error_message_not_export_ca, Toast.LENGTH_LONG).show(); + } + }); + }); + builder.setNegativeButton(R.string.activity_launch_button_cancel, (dialog, which) -> { + Activity activity = getActivity(); + if (activity != null) { + activity.finish(); + } + }); + return builder.create(); + } + + @Override + public void onStop() { + super.onStop(); + + Activity activity = getActivity(); + if (activity != null) { + activity.finish(); + } + } + + private void shareCA(final File fileName) { + ContentResolver resolver = getContext().getContentResolver(); + ContentValues values = new ContentValues(); + values.put(MediaStore.Downloads.TITLE, fileName.getName()); + values.put(MediaStore.Downloads.DISPLAY_NAME, fileName.getName()); + values.put(MediaStore.Downloads.DATE_TAKEN, System.currentTimeMillis()); + values.put(MediaStore.Downloads.MIME_TYPE, "application/x-pem-file"); + values.put(MediaStore.Downloads.IS_PENDING, 1); + Uri uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values); + if (uri == null) { + Log.e(TAG, "Failed to share ca: not inserted to ca store: path = " + fileName); + return; + } + + try (InputStream in = new FileInputStream(fileName); + OutputStream out = resolver.openOutputStream(uri)) { + if (out == null) { + Log.e(TAG, "Failed to share photo: no output stream: path = " + fileName); + return; + } + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + out.flush(); + } catch (FileNotFoundException e) { + throw new IllegalStateException(e); + } catch (IOException e) { + Log.e(TAG, "Failed to share photo: I/O error: path = " + fileName, e); + return; + } + + values.clear(); + values.put(MediaStore.Downloads.IS_PENDING, 0); + resolver.update(uri, values, null, null); + } +} diff --git a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values-ja/strings.xml b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values-ja/strings.xml index 5f691cfc73..8847b22478 100755 --- a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values-ja/strings.xml +++ b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values-ja/strings.xml @@ -277,4 +277,10 @@ はい いいえ アクセスログがありません + + + セキュリティの設定を開く + 証明書の手動インストール + Android11(R)以降、アプリケーションは認証局(CA)を自動的にインストールできなくなりました。\n\n設定で「セキュリティ>暗号化と視覚情報>証明書」のインストールの順に移動します。そこから「CA証明書」を選択肢新しくエクスポートした証明書ファイルを選択します。\n\n証明書は、外部ストレージのダウンロードフォルダにエクスポートしました。 + CA証明書の出力に失敗しました diff --git a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values/strings.xml b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values/strings.xml index 0c9efc550b..1badc2b5e8 100755 --- a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values/strings.xml +++ b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/res/values/strings.xml @@ -277,4 +277,11 @@ Yes No No Access Log + + + Open the security settings + Manual installation of certificates + Starting with Android 11(R), applications can no longer automatically install a Certificate Authority (CA). \n\nIn the settings, go to \"Security>Encryption and Visual Information>Install Certificates\". From there, select \"CA Certificates\" and select the newly exported certificate file.\n\nWe exported the certificate to the Downloads folder on our external storage. + Failed to output CA certificate. + From dbc7a3fda8924a5c2ac93ca9b805d2f20cf20057 Mon Sep 17 00:00:00 2001 From: TakayukiHoshi1984 Date: Tue, 2 Mar 2021 10:39:14 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E3=82=BB=E3=82=AD=E3=83=A5=E3=83=AA?= =?UTF-8?q?=E3=83=86=E3=82=A3=E3=81=AE=E8=A8=AD=E5=AE=9A=E7=94=BB=E9=9D=A2?= =?UTF-8?q?=E3=82=92=E9=96=8B=E3=81=8F=E3=82=88=E3=81=86=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/manager/setting/SecuritySettingDialogFragment.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java index a66eeb7c26..ccea01b371 100755 --- a/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java +++ b/dConnectManager/dConnectManager/dconnect-manager-app/src/main/java/org/deviceconnect/android/manager/setting/SecuritySettingDialogFragment.java @@ -60,9 +60,8 @@ public Dialog onCreateDialog(final Bundle savedInstanceState) { @Override public void onSuccess(@NonNull String s) { shareCA(new File(fileMgr.getBasePath(), "manager.pem")); - Intent installIntent = new Intent(Settings.ACTION_APP_SEARCH_SETTINGS); + Intent installIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - installIntent.putExtra(SearchManager.QUERY, "CA証明書"); startActivity(installIntent); }