2019年5月30日木曜日

android開発 シンプルなダイアログ表示

2019 Jun. 30.
2019 Jun. 29.
2019 Jun. 22.
2019 May 31.
2019 May 30.

参照元
https://developer.android.com/guide/topics/ui/dialogs
https://akira-watson.com/android/alertdialog.html
http://furudate.hatenablog.com/entry/2014/01/09/162421

[MainActivity]
  1. package YOUR.PACKAGE.alertdialogsample;
  2.  
  3. import android.app.AlertDialog;
  4. import android.app.Dialog;
  5. import android.content.DialogInterface;
  6. import android.support.annotation.NonNull;
  7. import android.support.v4.app.DialogFragment;
  8. import android.support.v4.app.FragmentManager;
  9. import android.support.v7.app.AppCompatActivity;
  10. import android.os.Bundle;
  11. import android.view.View;
  12. import android.widget.Button;
  13. import android.widget.TextView;
  14.  
  15.  
  16. public class MainActivity extends AppCompatActivity {
  17.  
  18. Button button_dialog1, button_dialog2, button_dialog3;
  19. private TextView text_view;
  20. private FragmentManager flagmentManager;
  21.  
  22. @Override
  23. protected void onCreate(Bundle savedInstanceState) {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_main);
  26.  
  27. text_view = findViewById(R.id.text_view);
  28. button_dialog1 = findViewById(R.id.button_dialog1);
  29. button_dialog2 = findViewById(R.id.button_dialog2);
  30. button_dialog3 = findViewById(R.id.button_dialog3);
  31.  
  32.  
  33. // button_dialog1ボタンタップでAlertを表示させる
  34. button_dialog1.setOnClickListener(new View.OnClickListener() {
  35. @Override
  36. public void onClick(View v) {
  37. flagmentManager = getSupportFragmentManager();
  38.  
  39. // DialogFragment を継承したAlertDialogFragment1のインスタンス
  40. AlertDialogFragment1 dialogFragment = AlertDialogFragment1.newInstance(100);
  41. // DialogFragmentの表示
  42. dialogFragment.show(flagmentManager, "test alert dialog1");
  43. }
  44. });
  45.  
  46.  
  47. // button_dialog2ボタンタップでダイアログのメッセージを変えたAlertを表示させる
  48. // newInstance()への引数を変更してメッセージを変える
  49. button_dialog2.setOnClickListener(new View.OnClickListener() {
  50. @Override
  51. public void onClick(View v) {
  52. flagmentManager = getSupportFragmentManager();
  53.  
  54. // DialogFragmentを継承したAlertDialogFragment2のインスタンス
  55. AlertDialogFragment1 dialogFragment = AlertDialogFragment1.newInstance(200);
  56. // DialogFragmentの表示
  57. dialogFragment.show(flagmentManager, "test alert dialog2");
  58. }
  59. });
  60.  
  61.  
  62. // button_dialog3ボタンタップでItemを選択するAlertを表示させる
  63. button_dialog3.setOnClickListener(new View.OnClickListener() {
  64. @Override
  65. public void onClick(View v) {
  66. flagmentManager = getSupportFragmentManager();
  67.  
  68. // DialogFragment を継承したAlertDialogFragmentのインスタンス
  69. AlertDialogFragment2 dialogFragment = new AlertDialogFragment2();
  70. // DialogFragmentの表示
  71. dialogFragment.show(flagmentManager, "test alert dialog");
  72. }
  73. });
  74. }
  75.  
  76.  
  77. public void setTextView(String message){
  78. text_view.setText(message);
  79. }
  80.  
  81.  
  82. /*
  83. * DialogFragmentを継承したクラスAlertDialogFragment1
  84. */
  85. public static class AlertDialogFragment1 extends DialogFragment {
  86.  
  87. /*
  88. * コンストラクタを記述してはならない。
  89. * newInstance()でのsetArguments、onCreateDialog()でのgetArgumentsを利用する。
  90. */
  91. public static AlertDialogFragment1 newInstance( int requestCode) {
  92. AlertDialogFragment1 fragment = new AlertDialogFragment1();
  93.  
  94. Bundle arguments = new Bundle();
  95. arguments.putInt("reqCode", requestCode);
  96. fragment.setArguments(arguments);
  97.  
  98. return fragment;
  99. }
  100.  
  101. @Override
  102. @NonNull
  103. public Dialog onCreateDialog(Bundle savedInstanceState) {
  104.  
  105. int requestCode = getArguments().getInt("reqCode");
  106.  
  107. AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
  108.  
  109. switch (requestCode) {
  110. case 100:
  111. alert.setTitle("Test AlertDialog1");
  112. alert.setMessage("Message is 100");
  113. break;
  114.  
  115. case 200:
  116. alert.setTitle("Test AlertDialog2");
  117. alert.setMessage("Message is 200");
  118. break;
  119.  
  120. }
  121. alert.setPositiveButton(R.string.dialog_ok, null);
  122.  
  123. return alert.create();
  124. }
  125. }
  126.  
  127.  
  128. /*
  129. * DialogFragmentを継承したクラスAlertDialogFragment2
  130. */
  131. public static class AlertDialogFragment2 extends DialogFragment {
  132. // 選択肢のリスト
  133. private String[] menulist = {"選択(1)","選択(2)","選択(3)"};
  134.  
  135. @Override
  136. @NonNull
  137. public Dialog onCreateDialog(Bundle savedInstanceState) {
  138.  
  139. AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
  140.  
  141. alert.setTitle("Test AlertDialog3");
  142. alert.setItems(menulist, new DialogInterface.OnClickListener() {
  143. @Override
  144. public void onClick(DialogInterface dialog, int idx) {
  145. // 選択1
  146. if (idx == 0) {
  147. setMassage(menulist[0]);
  148. }
  149. // 選択2
  150. else if (idx == 1) {
  151. setMassage(menulist[1]);
  152. }
  153. // 選択3, idx == 2
  154. else{
  155. setMassage(menulist[2]);
  156. }
  157. }
  158. });
  159. return alert.create();
  160. }
  161.  
  162.  
  163. private void setMassage(String message) {
  164. MainActivity mainActivity = (MainActivity) getActivity();
  165. if (mainActivity != null) {
  166. mainActivity.setTextView(message);
  167. }
  168. }
  169. }
  170. }

2019年5月26日日曜日

android開発  端末の外部ストレージ内のファイルに対しファイル名部分一致検索

2019 May 26.




  1. package YOUR.PACKAGE.APPLICATION;
  2.  
  3. /*
  4. * Re-use of https://akira-watson.com/android/file_search.html
  5. */
  6.  
  7. import android.os.Environment;
  8.  
  9. import java.io.File;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12.  
  13. public class SearchExternalStorageFile {
  14.  
  15. // 外部ストレージ内のfileStrにマッチするファイルを検索
  16. public String[] searchFiles( String fileStr ){
  17.  
  18. // マッチしたファイルの絶対パスを格納する
  19. List listMatchedFiles = new ArrayList<>();
  20. // String 型の ArrayList を生成
  21. List listDirectory = new ArrayList<>();
  22. // 外部ストレージのパスを取得する、パスは機種によって異なる
  23. File file = Environment.getExternalStorageDirectory();
  24. String storagePath = file.getPath();
  25. listDirectory.add(storagePath);
  26. int m = 0;
  27. int n = 0;
  28. String[] fileNames;
  29. String imgPath = null, fName;
  30. while(listDirectory.size() > m){
  31. File directory = new File(listDirectory.get(m));
  32. fileNames = directory.list();
  33. n = 0;
  34. while(fileNames.length > n){
  35. File subFile;
  36. subFile = new File(directory.getPath() + "/" + fileNames[n]);
  37. if (subFile.isDirectory()) {
  38. listDirectory.add(directory.getPath() + "/" + fileNames[n]);
  39. } else {
  40. if (fileNames[n].contains(fileStr)) {
  41. listMatchedFiles.add(directory.getPath() + "/" + fileNames[n]);
  42. }
  43. }
  44. n++;
  45. }
  46. m++;
  47. }
  48. int listSize = listMatchedFiles.size();
  49. return listMatchedFiles.toArray(new String[listSize]);
  50. }
  51. }

java 時間フォーマット

2019 May 26.

Java で 24時間表記の場合の時間は kk とする。
 例 DateFormat.format("yyyy-MM-dd_kk:mm:ss", dateTaken).toString()

2019年5月25日土曜日

android開発 カメラ起動・写真撮影

2019 May 25.

"AndroidManifest.xml"
 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="YOUR.PACKAGE.sampletakephotogetimagefile">
    <uses-feature android:name="android.hardware.camera" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.hardware.camera.autofocus" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>




  1. package YOUR.PACKAGE.sampletakephotogetimagefile;
  2. import android.Manifest;
  3. import android.annotation.TargetApi;
  4. import android.content.ContentResolver;
  5. import android.content.ContentValues;
  6. import android.content.Intent;
  7. import android.content.pm.PackageManager;
  8. import android.database.Cursor;
  9. import android.net.Uri;
  10. import android.os.Build;
  11. import android.provider.MediaStore;
  12. import android.support.annotation.NonNull;
  13. import android.support.v7.app.AppCompatActivity;
  14. import android.os.Bundle;
  15. import android.text.format.DateFormat;
  16. import android.view.View;
  17. import android.widget.Button;
  18. import android.widget.ImageView;
  19. import android.widget.TextView;
  20. import android.widget.Toast;
  21.  
  22. public class MainActivity extends AppCompatActivity {
  23.  
  24. Button button_take_photo;
  25. ImageView image_view;
  26. TextView text_view_uri_path, text_view_file_path, text_view_image_title;
  27. static final int REQUEST_CAPTURE_IMAGE = 100;
  28. private final int REQUEST_PERMISSION__EX_STORAGE = 1000;
  29. private final int REQUEST_PERMISSION_CAMERA = 1010;
  30.  
  31. Uri pictureUri;
  32.  
  33. @Override
  34. protected void onCreate(Bundle savedInstanceState) {
  35. super.onCreate(savedInstanceState);
  36. setContentView(R.layout.activity_main);
  37.  
  38. findViews();
  39.  
  40. // check & get permissions
  41. if(Build.VERSION.SDK_INT >= 23){
  42. checkPermission();
  43. }
  44. if (checkSelfPermission(Manifest.permission.CAMERA) !=
  45. PackageManager.PERMISSION_GRANTED){
  46. button_take_photo.setText(R.string.button_unable_phote );
  47. button_take_photo.setEnabled(false);
  48. }
  49.  
  50. setListeners();
  51. }
  52.  
  53.  
  54. protected void findViews(){
  55. button_take_photo = findViewById(R.id.button_take_photo);
  56. image_view = findViewById(R.id.imageView);
  57. text_view_uri_path = findViewById(R.id.textViewUriPath);
  58. text_view_file_path = findViewById(R.id.textViewFilePath);
  59. text_view_image_title = findViewById(R.id.textViewImageTitle);
  60. }
  61.  
  62.  
  63. // Permissionの確認
  64. // from https://akira-watson.com/android/mediastore.html
  65. @TargetApi(Build.VERSION_CODES.M)
  66. public void checkPermission() {
  67. if (checkSelfPermission(Manifest.permission.CAMERA) !=
  68. PackageManager.PERMISSION_GRANTED){
  69. requestCameraPermission();
  70. }
  71. if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
  72. PackageManager.PERMISSION_GRANTED){
  73. requestExStoragePermission();
  74. }
  75. }
  76.  
  77.  
  78. // CameraPermission許可を求める
  79. @TargetApi(Build.VERSION_CODES.M)
  80. private void requestCameraPermission() {
  81. if (shouldShowRequestPermissionRationale( Manifest.permission.CAMERA)) {
  82. requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_PERMISSION_CAMERA);
  83.  
  84. } else {
  85. Toast toast = Toast.makeText(this, "許可されないとアプリが実行できません",
  86. Toast.LENGTH_SHORT);
  87. toast.show();
  88. requestPermissions(new String[]{Manifest.permission.CAMERA }, REQUEST_PERMISSION_CAMERA);
  89. }
  90. }
  91.  
  92.  
  93. // ExternalStoragePermission許可を求める
  94. @TargetApi(Build.VERSION_CODES.M)
  95. private void requestExStoragePermission() {
  96. if (shouldShowRequestPermissionRationale( Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
  97. requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
  98. REQUEST_PERMISSION__EX_STORAGE);
  99.  
  100. } else {
  101. Toast toast = Toast.makeText(this, "許可されないとアプリが実行できません",
  102. Toast.LENGTH_SHORT);
  103. toast.show();
  104. requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE },
  105. REQUEST_PERMISSION__EX_STORAGE);
  106. }
  107. }
  108.  
  109.  
  110. // requestPermission結果に対する処理
  111. @Override
  112. public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions,
  113. @NonNull int[] grantResults) {
  114. if (requestCode == REQUEST_PERMISSION_CAMERA) {
  115. if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
  116. // 拒否された時の対応
  117. Toast toast = Toast.makeText(this, "これ以上なにもできません",
  118. Toast.LENGTH_SHORT);
  119. toast.show();
  120. }
  121. } else if (requestCode == REQUEST_PERMISSION__EX_STORAGE) {
  122. if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
  123. // 拒否された時の対応
  124. Toast toast = Toast.makeText(this, "これ以上なにもできません",
  125. Toast.LENGTH_SHORT);
  126. toast.show();
  127. }
  128. } else {
  129. Toast toast = Toast.makeText(this,
  130. "Bad requestCode", Toast.LENGTH_SHORT);
  131. toast.show();
  132. }
  133. }
  134.  
  135.  
  136. protected void setListeners(){
  137. // カメラ起動ボタンが押された時
  138. button_take_photo.setOnClickListener(new View.OnClickListener() {
  139.  
  140. @Override
  141. public void onClick(View v) {
  142. /*
  143. 写真用情報を収集し、ContentResolverを使ってandroidに備わっている
  144. MediaStore.Images.Mediaデータベースに写真用情報を追加し、そのURI
  145. を取得する
  146. */
  147. long dateTaken = System.currentTimeMillis();
  148. String filename = DateFormat.format("yyyy-MM-dd_kk:mm:ss", dateTaken).toString() + ".jpg";
  149. ContentResolver contentResolver = getContentResolver();
  150. ContentValues values = new ContentValues(5);
  151. values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
  152. values.put(MediaStore.Images.Media.DATE_MODIFIED, System.currentTimeMillis()/1000);
  153. values.put(MediaStore.Images.Media.TITLE, filename);
  154. values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
  155. values.put(MediaStore.Images.Media.DATE_TAKEN,System.currentTimeMillis());
  156. pictureUri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
  157.  
  158. // カメラを起動する
  159. Intent intent = new Intent();
  160. intent.setAction("android.media.action.IMAGE_CAPTURE");
  161. intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
  162. // MediaStore.EXTRA_OUTPUTで指定したpictureUriに、撮影後に画像データが書き込まれる
  163. startActivityForResult(intent, REQUEST_CAPTURE_IMAGE);
  164. }
  165. });
  166. }
  167.  
  168.  
  169. // このアクティビティから起動された他の機能から戻ってきた時の処理
  170. @Override
  171. protected void onActivityResult(int requestCode, int resultCode, Intent data ) {
  172.  
  173. /*
  174. 正しい結果が得られなかった場合の処理
  175. 撮影キャンセルなどするとこっちに来る
  176. */
  177. if (resultCode != RESULT_OK) {
  178.  
  179. // カメラ撮影からの復帰の時
  180. if (requestCode == REQUEST_CAPTURE_IMAGE) {
  181. Toast toast = Toast.makeText(this,"resultCode != RESULT_OK",
  182. Toast.LENGTH_LONG);
  183. toast.show();
  184. return;
  185. }
  186. }
  187.  
  188. /*
  189. * 写真撮影できた場合
  190. */
  191. if (requestCode == REQUEST_CAPTURE_IMAGE) {
  192. if (data == null ) {
  193. Toast.makeText(this, "data == null ",
  194. Toast.LENGTH_SHORT).show();
  195.  
  196. } else if ( data.getData() == null) {
  197. Toast.makeText(this, "data.getData() == null",Toast.LENGTH_SHORT).show();
  198. }
  199.  
  200. // 撮影した写真を取り出す
  201. image_view.setImageURI(pictureUri);
  202. text_view_uri_path.setText("Uri path: " + pictureUri.getPath());
  203.  
  204. // get filepath & title from uri
  205. ContentResolver contentResolver = this.getContentResolver();
  206. String[] columns =
  207. {
  208. MediaStore.Images.Media.DATA,
  209. MediaStore.Images.Media.TITLE
  210. };
  211. Cursor cursor = contentResolver.query(pictureUri, columns, null,
  212. null, null);
  213. if(cursor == null) return;
  214. int pathIndex = cursor.getColumnIndex( MediaStore.Images.Media.DATA);
  215. int titleIndex = cursor.getColumnIndex( MediaStore.Images.Media.TITLE);
  216. cursor.moveToFirst();
  217. String filePath = cursor.getString(pathIndex);
  218. String imageTitle = cursor.getString(titleIndex);
  219.  
  220. text_view_file_path.setText(filePath);
  221. text_view_image_title.setText(imageTitle);
  222.  
  223. return;
  224. }
  225. }
  226. }

android開発 permission取得

2019 May 25.

"AndroidManifest.xml"
 <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxx.xxx.sampletakephotogetimagefile">
    <uses-feature android:name="android.hardware.camera" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.hardware.camera.autofocus" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>



  1. if(Build.VERSION.SDK_INT >= 23){
  2. checkPermission();
  3. }
  4. PROCESS_AFTER_GETTING_PERMISSIONS
  5.  
  6.  
  7. // Permissionの確認
  8. // reuse of https://akira-watson.com/android/mediastore.html
  9. @TargetApi(Build.VERSION_CODES.M)
  10. public void checkPermission() {
  11. if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED){
  12. requestCameraPermission();
  13. }
  14. if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
  15. requestExStoragePermission();
  16. }
  17. }
  18.  
  19. // CameraPermission許可を求める
  20. @TargetApi(Build.VERSION_CODES.M)
  21. private void requestCameraPermission() {
  22. if (shouldShowRequestPermissionRationale( Manifest.permission.CAMERA)) {
  23. requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_PERMISSION_CAMERA);
  24.  
  25. } else {
  26. Toast toast = Toast.makeText(this, "許可されないとアプリが実行できません", Toast.LENGTH_SHORT);
  27. toast.show();
  28. requestPermissions(new String[]{Manifest.permission.CAMERA }, REQUEST_PERMISSION_CAMERA);
  29. }
  30. }
  31.  
  32. // ExternalStoragePermission許可を求める
  33. @TargetApi(Build.VERSION_CODES.M)
  34. private void requestExStoragePermission() {
  35. if (shouldShowRequestPermissionRationale( Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
  36. requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION__EX_STORAGE);
  37.  
  38. } else {
  39. Toast toast = Toast.makeText(this, "許可されないとアプリが実行できません", Toast.LENGTH_SHORT);
  40. toast.show();
  41. requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE }, REQUEST_PERMISSION__EX_STORAGE);
  42. }
  43. }
  44.  
  45.  
  46. // requestPermission結果に対する処理
  47. @Override
  48. public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
  49. if (requestCode == REQUEST_PERMISSION_CAMERA) {
  50. if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
  51. // 拒否された時の対応
  52. Toast toast = Toast.makeText(this, "これ以上なにもできません", Toast.LENGTH_SHORT);
  53. toast.show();
  54. }
  55. } else if (requestCode == REQUEST_PERMISSION__EX_STORAGE) {
  56. if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
  57. // 拒否された時の対応
  58. Toast toast = Toast.makeText(this, "これ以上なにもできません", Toast.LENGTH_SHORT);
  59. toast.show();
  60. }
  61. } else {
  62. Toast toast = Toast.makeText(this, "Bad requestCode", Toast.LENGTH_SHORT);
  63. toast.show();
  64. }
  65. }

ファイル修正時刻が現在時刻からn分前以内のファイルを検索

2019 May 25.

$ find DIR/ -mmin -N
    N: さかのぼる時間(単位:分)

2019年5月19日日曜日

ユーザーからの文字列入力を受け取るダイアログ android開発

2019 May 19.

https://www.ipentec.com/document/android-custom-dialog-using-dialogfragment-return-value より

[activity_main.xml]

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textViewPhrase"
        android:layout_width="0dp"
        android:layout_height="66dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.118" />

</android.support.constraint.ConstraintLayout>



[input_text_dialog.xml]

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textViewPhraseLabel"
        android:layout_width="132dp"
        android:layout_height="27dp"
        android:text="Input text"
        app:layout_constraintBottom_toTopOf="@+id/editTextPhrase"
        tools:layout_editor_absoluteX="8dp" />

    <EditText
        android:id="@+id/editTextPhrase"
        android:layout_width="381dp"
        android:layout_height="52dp"
        android:layout_marginTop="268dp"
        android:ems="10"
        android:inputType="text"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="8dp" />

    <Button
        android:id="@+id/buttonOK"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="52dp"
        android:layout_marginEnd="8dp"
        android:text="OK"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editTextPhrase" />
</android.support.constraint.ConstraintLayout>



MainActivity.java
  1. package YOUR.PACKAGE;
  2.  
  3. import android.support.v7.app.AppCompatActivity;
  4. import android.os.Bundle;
  5. import android.widget.TextView;
  6.  
  7. public class MainActivity extends AppCompatActivity {
  8.  
  9. boolean is1stRun = true;
  10.  
  11. @Override
  12. protected void onCreate(Bundle savedInstanceState) {
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.activity_main);
  15.  
  16. if ( is1stRun ) {
  17. // get text by dialog
  18. InputTextDialogFragment cdf = new InputTextDialogFragment();
  19. cdf.show(getSupportFragmentManager(),"dialog");
  20. is1stRun = false;
  21. }
  22. }
  23.  
  24.  
  25. public void onReturnValue(String value) {
  26. TextView textViewPhrase = (TextView)findViewById(R.id.textViewPhrase);
  27. textViewPhrase.setText(value);
  28. }
  29.  
  30. }

InputTextDialogFragment.java
  1. package YOUR.PACKAGE;
  2.  
  3. import android.app.Dialog;
  4. import android.os.Bundle;
  5. import android.support.v4.app.DialogFragment;
  6. import android.view.View;
  7. import android.view.Window;
  8. import android.view.WindowManager;
  9. import android.widget.EditText;
  10.  
  11. public class InputTextDialogFragment extends DialogFragment {
  12. EditText editTextPhrase;
  13.  
  14. @Override
  15. public Dialog onCreateDialog(Bundle savedInstanceState) {
  16. Dialog dialog = new Dialog(getActivity());
  17. dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
  18. dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  19. WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
  20. dialog.setContentView(R.layout.input_text_dialog);
  21.  
  22. editTextPhrase = (dialog.findViewById(R.id.editTextPhrase));
  23.  
  24. dialog.findViewById(R.id.buttonOK).setOnClickListener(new View.OnClickListener() {
  25. @Override
  26. public void onClick(View v) {
  27.  
  28. String textPhrase = editTextPhrase.getText().toString();
  29. MainActivity callingActivity = (MainActivity) getActivity();
  30. callingActivity.onReturnValue(textPhrase);
  31.  
  32. dismiss();
  33. }
  34. });
  35.  
  36. return dialog;
  37. }
  38. }

2019年5月6日月曜日

Android Studioのエラー対処

2019 May 06.

対処法
Settings -> Instant Run -> Set "Instant Run" false

エラー表示内容
execution failed for task
execute transform
java.lang.RuntimeException: java.lang.RuntimeException: java.io.FileNotFoundException: /home/xxx/AndroidStudioProjects/MyApp/app/build/intermediates/instant_run_split_apk_resources/debug/instantRunSplitApkResourcesDebug/out/slice_9/resources_ap

android開発 外部ストーリッジ/SDカードのパスの取得

2019 May 06.

https://qiita.com/h_yama37/items/11b8658b2de9625200aa より


  1. private final Context AppContext;
  2. private final String file;
  3.  
  4. // android端末内の外部ストーリッジ確認
  5. List sdCardFilesDirPaths = SdCardDirPaths.getSdCardFilesDirPathListForLollipop( AppContext );
  6. Collections.sort(sdCardFilesDirPaths, new CompStringLength());
  7. for (String p : sdCardFilesDirPaths) {
  8. Log.d("My", "SDパスの1つ: " + p);
  9. }
  10. externalPath = sdCardFilesDirPaths.get(0);
  11. externalPath = externalPath.replaceAll("/Android.*$", "");
  12. Log.d("My", "SDパス: " + externalPath);
  13. // get filePath
  14. final String sourcePath = externalPath + "/" + file;
  15. Log.d("My", "sourcePath " + sourcePath );
  16. if ( new File(sourcePath).exists()) {
  17. Log.d("My", sourcePath + " exists.");
  18. } else {
  19. Log.d("My", sourcePath + " not exist.");
  20. }

SdCardDirPaths.java
  1. import android.annotation.TargetApi;
  2. import android.content.Context;
  3. import android.os.Build;
  4. import android.os.Environment;
  5. import android.util.Log;
  6.  
  7. import java.io.File;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10.  
  11. public class SdCardDirPaths {
  12. /**
  13. * SDカードのfilesディレクトリパスのリストを取得する。
  14. * Android5.0以上対応。
  15. *
  16. * @param context
  17. * @return SDカードのfilesディレクトリパスのリスト
  18. */
  19. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  20. public static List getSdCardFilesDirPathListForLollipop(Context context) {
  21. List sdCardFilesDirPathList = new ArrayList<>();
  22. // getExternalFilesDirsはAndroid4.4から利用できるAPI。
  23. // filesディレクトリのリストを取得できる。
  24. File[] dirArr = context.getExternalFilesDirs(null);
  25. for (File dir : dirArr) {
  26. if (dir != null) {
  27. String path = dir.getAbsolutePath();
  28. Log.d("My", "Externalパスの1つ: " + path);
  29. // isExternalStorageRemovableはAndroid5.0から利用できるAPI。
  30. // 取り外し可能かどうか(SDカードかどうか)を判定している。
  31. if (Environment.isExternalStorageRemovable(dir)) {
  32. // 取り外し可能であればSDカード。
  33. if (!sdCardFilesDirPathList.contains(path)) {
  34. sdCardFilesDirPathList.add(path);
  35. }
  36. } else {
  37. // 取り外し不可能であれば内部ストレージ。
  38. }
  39. }
  40. }
  41. return sdCardFilesDirPathList;
  42. }
  43. }

CompStringLength.java
  1. import java.util.Comparator;
  2.  
  3. public class CompStringLength implements Comparator {
  4. @Override
  5. public int compare(String first, String second){
  6. //null評価
  7. //両方nullなら等価とする
  8. if(first == null && second == null){
  9. return 0;
  10. }
  11. //片方nullなら、nullを小さいとする。
  12. if(first == null){
  13. return -1;
  14. }else if(second == null){
  15. return 1;
  16. }
  17. //idの文字列長でソート。文字列数がが小さい順に並べる。
  18. if(first.length() > second.length()){
  19. return 1;
  20. }else if(first.length() < second.length()){
  21. return -1;
  22. }else if(first.length() == second.length()){
  23. return 0;
  24. }
  25. return 0;
  26. }
  27. }

2019年5月3日金曜日

android開発 メモリリークを防ぐWeakReference

2019 May 03.


FirstActivity.java
(OnClickListener等は省略)


  1. public class FirstActivity extends AppCompatActivity {
  2. Button button1 = (Button) findViewById(R.id.button1);
  3. button1.setEnabled(true);
  4. TextView textView1 = (TextView) findViewById(R.id.textView1);
  5. textView1.setText("start")
  6.  
  7. new SecondTask(this).execute();
  8. }

SecondTask.java
  1. public class SecondTask extends AsyncTask {
  2. private WeakReference weakReference;
  3.  
  4. /**
  5. * make WeakReference in constructor
  6. * 参照しているActivityを引数にしてWeakReferenceのインスタンスを生成する
  7. **/
  8. SecondTask(Context referenceContext) {
  9. private WeakReference weakReference;
  10. weakReference = new WeakReference<>(referenceContext);
  11. }
  12.  
  13. /**
  14. * use of WeakReference in onPostExecute
  15. * weakReference.get()で参照しているActivityのContextを取得し、それを通じてView を設定したりする
  16. **/
  17. @Override
  18. protected void onPostExecute(String result) {
  19. Activity activity = (Activity) weakReference.get();
  20.  
  21. if (activity == null || activity.isFinishing()) return;
  22.  
  23. activity.findViewById(R.id.button1).setEnabled(false);
  24. TextView tv = activity.findViewById(R.id.textView1);
  25. tv.setText("end");
  26. }
  27. }

2019年5月2日木曜日

JAVA JSch SFTP AndroidクライアントからSSHサーバーへのファイル転送

2019 May. 03.
2019 May. 02.

https://qiita.com/nenokido2000/items/a00348c9f6a0f942773b より




MainActivity.java

  1. package YOUR.PACKAGE.NAME;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.widget.Button;
  6. import android.widget.TextView;
  7.  
  8. public class MainActivity extends AppCompatActivity {
  9.  
  10.  
  11. /** Channel接続タイプ */
  12. private static final String CHANNEL_TYPE = "sftp";
  13.  
  14. private MyTask task;
  15.  
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19.  
  20. setContentView(R.layout.activity_main);
  21.  
  22. /*
  23. final String ServerIP = "ServerIP";
  24. final int Port = PortNum;
  25. final String UserId = "USER";
  26. final String PassPhrase = "YOURPASSPHRASE";
  27. final String IdentityKeyPath = "YOUR/SECRET/FILE/PATH"; // Do not attach '/' at head of path
  28. final String SourcePath = "PATH/TO/SOURCE/FILE"; // Do not attach '/' at head of path
  29. final String DestPath = "PATH/TO/DEST/FILE";
  30. */
  31.  
  32. final String ServerIP="";
  33. final int Port = ;
  34. final String UserId = "";
  35. final String PassPhrase = "";
  36. final String IdentityKeyPath = "";
  37. final String SourcePath = "";
  38. final String DestPath = "";
  39.  
  40. Button button1= (Button) findViewById(R.id.button1);
  41. TextView textView1 = (TextView) findViewById(R.id.textView1);
  42.  
  43. // タスクの生成
  44. task = new MyTask(ServerIP, Port, UserId, PassPhrase, IdentityKeyPath, SourcePath, DestPath,this);
  45.  
  46. button1.setOnClickListener(new View.OnClickListener() {
  47. @Override
  48. public void onClick(View v) {
  49. v.setEnabled(false);
  50. // 非同期処理を開始する
  51. task.execute();
  52. }
  53. });
  54. }
  55. }


MyTask.java
  1. package YOUR.PACKAGE.NAME;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.os.AsyncTask;
  5. import android.widget.TextView;
  6.  
  7. import com.jcraft.jsch.JSchException;
  8.  
  9. import java.lang.ref.WeakReference;
  10.  
  11. public class MyTask extends AsyncTask {
  12. private final String ServerIp;
  13. private final int Port;
  14. private final String User;
  15. private final String IdentityKeyPath;
  16. private final String PassPhrase;
  17. private final String SrcPath;
  18. private final String DestPath;
  19. private WeakReference weakReference;
  20. // constructor
  21. MyTask(final String ServerIp, final int Port, final String User,
  22. final String PassPhrase, final String IdentityKeyPath, final String SrcPath,
  23. final String DestPath, Context referenceContext) {
  24. super();
  25. // 呼び出し元へのweakReference
  26. weakReference = new WeakReference<>(referenceContext);
  27. this.ServerIp = ServerIp;
  28. this.Port = Port;
  29. this.User = User;
  30. this.PassPhrase = PassPhrase;
  31. this.IdentityKeyPath = IdentityKeyPath;
  32. this.SrcPath = SrcPath;
  33. this.DestPath = DestPath;
  34. }
  35. /**
  36. * バックグランドで行う処理
  37. */
  38. @Override
  39. protected String doInBackground(Void... value) {
  40. // startJsch
  41. MyJsch mJsch = new MyJsch( ServerIp, Port, User, PassPhrase, IdentityKeyPath, SrcPath,
  42. DestPath, weakReference.get());
  43. try {
  44. mJsch.putFile();
  45. } catch (JSchException e) {
  46. e.printStackTrace();
  47. return e.toString();
  48. }
  49. return "Success";
  50. }
  51. /**
  52. * バックグランド処理が完了し、UIスレッドに反映する
  53. */
  54. @Override
  55. protected void onPostExecute(String result) {
  56. // get a reference to the activity if it is still there
  57. Activity activity = (Activity) weakReference.get();
  58. if (activity == null || activity.isFinishing()) return;
  59. activity.findViewById(R.id.button1).setEnabled(true);
  60. TextView tv = activity.findViewById(R.id.textView1);
  61. tv.setText(result);
  62. }
  63. }


MyJsch.java
  1. package YOUR.PACKAGE.NAME;
  2. import android.content.Context;
  3. import android.util.Log;
  4.  
  5. import com.jcraft.jsch.Channel;
  6. import com.jcraft.jsch.ChannelSftp;
  7. import com.jcraft.jsch.JSch;
  8. import com.jcraft.jsch.JSchException;
  9. import com.jcraft.jsch.Session;
  10. import com.jcraft.jsch.SftpException;
  11. import com.jcraft.jsch.UserInfo;
  12.  
  13. import java.io.File;
  14. import java.util.Collections;
  15. import java.util.List;
  16.  
  17. public class MyJsch {
  18. private final String ServerIp;
  19. private final int Port;
  20. private final String User;
  21. private final String PassPhrase;
  22. private final String IdentityKeyPath;
  23. private final String SrcPath;
  24. private final String DestPath;
  25. private Context activityContext;
  26.  
  27. private String externalPath;
  28.  
  29. /** Channel接続タイプ */
  30. private static final String CHANNEL_TYPE = "sftp";
  31.  
  32. /**
  33. * コンストラクタ
  34. */
  35. MyJsch(final String ServerIp, final int Port, final String User, final String PassPhrase,
  36. final String IdentityKeyPath, final String SrcPath, final String DestPath,
  37. Context activityContext) {
  38. this.ServerIp = ServerIp;
  39. this.Port = Port;
  40. this.User = User;
  41. this.IdentityKeyPath = IdentityKeyPath;
  42. this.PassPhrase = PassPhrase;
  43. this.SrcPath = SrcPath;
  44. this.DestPath = DestPath;
  45. this.activityContext = activityContext;
  46. }
  47.  
  48.  
  49. /**
  50. * ファイルアップロード
  51. *
  52. * @throws JSchException
  53. * Session・Channelの設定/接続エラー時に発生
  54. */
  55. public void putFile()
  56. throws JSchException {
  57.  
  58. Session session = null;
  59. ChannelSftp channel = null;
  60.  
  61.  
  62. // 外部ストーリッジ確認
  63. List sdCardFilesDirPaths =
  64. SdCardDirPaths.getSdCardFilesDirPathListForLollipop( activityContext );
  65. Collections.sort(sdCardFilesDirPaths, new CompStringLength());
  66. for (String p : sdCardFilesDirPaths) {
  67. Log.d("My", "SDパスの1つ: " + p);
  68. }
  69. externalPath = sdCardFilesDirPaths.get(0);
  70. externalPath = externalPath.replaceAll("/Android.*$", "");
  71. Log.d("My", "SDパス: " + externalPath);
  72. // get sourcePath
  73. final String sourcePath = externalPath + "/" + SrcPath;
  74. Log.d("My", "sourcePath " + sourcePath );
  75. if ( new File(sourcePath).exists()) {
  76. Log.d("My", sourcePath + " exists.");
  77. } else {
  78. Log.d("My", sourcePath + " not exist.");
  79. }
  80. /*
  81. * sftp通信を実行
  82. */
  83. try {
  84. session = connectSession();
  85. channel = connectChannelSftp(session);
  86. String absoluteDestPath = channel.getHome() + "/" + DestPath;
  87. String destFile = new File(absoluteDestPath).getName();
  88. int numDestPath = absoluteDestPath.length();
  89. int numDestFile = destFile.length();
  90. String destParentPath = absoluteDestPath.substring( 0, numDestPath - numDestFile );
  91. Log.d("My", "absoluteDestPath is " + absoluteDestPath);
  92. Log.d("My", "destFile is " + destFile);
  93. Log.d("My", "destParentPath is " + destParentPath);
  94. Log.d("My", "current local directory is " + channel.lpwd());
  95. Log.d("My", "remote home directory is " + channel.getHome());
  96. channel.cd(destParentPath);
  97. channel.put(sourcePath, destFile);
  98. try {
  99. channel.lstat(destFile);
  100. } catch (SftpException e) {
  101. Log.d("My", DestPath + " does not exist.");
  102. Log.d("My", e.toString());
  103. }
  104. } catch (SftpException e) {
  105. Log.d("My",e.toString());
  106. } finally {
  107. disconnect(session, channel);
  108. }
  109. }
  110. /**
  111. * Sessionを開始
  112. */
  113. private Session connectSession()
  114. throws JSchException {
  115. final JSch jsch = new JSch();
  116. // 鍵追加
  117. String keyFilePath = externalPath + "/" + IdentityKeyPath;
  118. if ( new File(keyFilePath).exists()) {
  119. Log.d("My", keyFilePath + " exists.");
  120. } else {
  121. Log.d("My", keyFilePath + " not exist.");
  122. }
  123. jsch.addIdentity(keyFilePath, PassPhrase);
  124. // Session設定
  125. final Session session = jsch.getSession(User, ServerIp, Port);
  126. final UserInfo userInfo = new SftpUserInfo();
  127. // TODO 今回は使用しないがパスフレーズ等が必要な場合はUserInfoインスタンス経由で設定する
  128. session.setUserInfo(userInfo);
  129. session.connect();
  130. return session;
  131. }
  132. /**
  133. * SFTPのChannelを開始
  134. *
  135. * @param session
  136. * 開始されたSession情報
  137. */
  138. private ChannelSftp connectChannelSftp(final Session session)
  139. throws JSchException {
  140. final ChannelSftp channel = (ChannelSftp) session.openChannel(CHANNEL_TYPE);
  141. try {
  142. channel.connect();
  143. } catch (JSchException e) {
  144. Log.d("My", e.toString());
  145. }
  146. return channel;
  147. }
  148. /**
  149. * Session・Channelの終了
  150. *
  151. * @param session
  152. * 開始されたSession情報
  153. * @param channels
  154. * 開始されたChannel情報.複数指定可能
  155. */
  156. private void disconnect(final Session session, final Channel... channels) {
  157. if (channels != null) {
  158. for (Channel c: channels ) {
  159. if (c != null) {
  160. c.disconnect();
  161. }
  162. }
  163. }
  164. if (session != null) {
  165. session.disconnect();
  166. }
  167. }
  168. /**
  169. * SFTPに接続するユーザ情報を保持するクラス
  170. */
  171. private static class SftpUserInfo implements UserInfo {
  172. @Override
  173. public String getPassword() {
  174. return null;
  175. }
  176. @Override
  177. public boolean promptPassword(String arg0) {
  178. return true;
  179. }
  180. @Override
  181. public boolean promptPassphrase(String arg0) {
  182. return true;
  183. }
  184. @Override
  185. public boolean promptYesNo(String arg0) {
  186. return true;
  187. }
  188. @Override
  189. public void showMessage(String arg0) {
  190. }
  191. @Override
  192. public String getPassphrase() {
  193. return null;
  194. }
  195. }
  196. }

JAVA JSch sftp sshサーバーへのファイル転送時のサーバー側ディレクトリ・ファイルの指定要領

2019 May 02.

sftp接続後、サーバーのカレントディレクトリを転送先ディレクトリに変更(ChannelSftp#cd)した上で、ファイル転送する。
ファイル転送コマンド(ChannelSftp#put)内でパスを記述できない。