ラベル android の投稿を表示しています。 すべての投稿を表示
ラベル android の投稿を表示しています。 すべての投稿を表示

2019年11月2日土曜日

iPhoneからandroidへのファイル転送

2019 Nov. 02.
android端末でブラウザを起動する。
https://www.icloud.com/ にアクセスしiPhoneのApple IDでログインする。
目的のファイルをダウンロードする。ダウンロード時に指定するアプリはブラウザにする。
android端末内部共有ストレージ/Download ディレクトリ内にファイルが保管される。

2019年8月18日日曜日

Android AsyncTaskの処理完了時に実行する処理のプログラム

2019 Aug. 18.
2019 Aug. 17.

(参考サイト)
https://teratail.com/questions/195681
https://akira-watson.com/android/asynctask.html


(MyActivity.java)


public class MyActivity extends AppCompatActivity {

    Button buttonOK;

    /*
     * MyAsyncTask内のListenerインターフェースを呼び出す
     */
    private MyAsyncTask.Listener createListener() {
        return new MyAsyncTask.Listener() {

            /*
             * Listenerインターフェースの抽象メソッドonSuccessにコードを実装
             */
            @Override
            public void onSuccess(String result) {
                CODES_TO_RUN_AFTER_MyAsyncTask;
            }
        };
    }

    /*
     * buttonOKがタップされたらMyAsyncTaskが呼び出される
     */
    buttonOK.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            myAsyncTask = new MyAsyncTask();

            /*
             * MyAsyncTask内のListenerインターフェース型変数listenerに
             * createListener()をセットする
             *     createListener()ではListenerインターフェースの
             *     抽象メソッドonSuccessの実装コードが記述されている。
             *     MyAsyncTask内で"listener.onSuccess()"によって実装コードを実行できる。
             */
            myAsyncTask.setListener(createListener());
            myAsyncTask.execute();
        }
    });

}
(MyAsyncTask.java)
public class MyAsyncTask extends AsyncTask {
    private Listener listener;

    /*
     * 抽象メソッドonSuccess()は、MyAsyncTask内で実行させたい処理。
     * 抽象メソッドonSuccess()は、MyAsyncTaskを呼び出すMyActivity内の
     * createListener()内で実装されている。
     */
    interface Listener {
        void onSuccess(String str);
    }
   
    void setListener(Listener listener) {
        this.listener = listener;
    }

    @Override
    protected String doInBackground(Void... params) {
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        CODES_TO_EXECUTE_onPostExecute;

        /*
         * onSuccess()メソッド実行
         */
        listener.onSuccess(result);
        return;
    }
}

2019年7月15日月曜日

android AsyncTaskによるJSchを用いたSSH通信とAsyncTask内イベントの呼び出し元クラスでのキャッチ

2019 Jul. 15.

MyJsch.java
package your.package;

import android.content.Context;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.UserInfo;

import java.io.File;
import java.io.InputStream;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;

class MyJsch {
    private final String ServerIp;
    private final int Port;
    private final String User;
    private final String PassPhraseWord;
    private final String IdentityKeyPath;
    private final Context AppContext;

    /** Channel接続タイプ */
    private static final String CHANNEL_TYPE = "sftp";

    /*
     * コンストラクタ
     */
    MyJsch( final String ServerIp, final int Port, final String User, final String PassPhraseWord,
            final String IdentityKeyPath, final Context AppContext) {
        this.ServerIp = ServerIp;
        this.Port = Port;
        this.User = User;
        this.PassPhraseWord = PassPhraseWord;
        this.IdentityKeyPath = IdentityKeyPath;
        this.AppContext = AppContext;
    }


    /*
     * Sessionを開始
     */
    protected Session connectSession() throws JSchException {
        Session session = null;

        // android端末内の外部ストーリッジ確認
        List sdCardFilesDirPaths =
                SdCardDirPaths.getSdCardFilesDirPathListForLollipop( AppContext );
        Collections.sort(sdCardFilesDirPaths, new CompStringLength());
        String externalPath = sdCardFilesDirPaths.get(0);
        externalPath = externalPath.replaceAll("/Android.*$", "");

        final JSch jsch = new JSch();

        // クライアント側のknownHostsチェックを行わない
        Hashtable config = new Hashtable();
        config.put("StrictHostKeyChecking", "no");
        jsch.setConfig(config);

        // パスフレーズ・秘密鍵方式
        String privKeyFilePath = externalPath + "/" + IdentityKeyPath;
        File privKeyFile = new File(privKeyFilePath);
        if (privKeyFile.exists() ) {
            jsch.addIdentity(privKeyFilePath, PassPhraseWord);
        }

        // Session取得
        session = jsch.getSession(User, ServerIp, Port);

        // パスワード方式でも可とする
        session.setPassword(PassPhraseWord);

        final UserInfo userInfo = new SftpUserInfo();
        session.setUserInfo(userInfo);
        session.connect();
        return session;
    }


    /**
     * SFTPのChannelを開始
     *
     * @param session
     *            開始されたSession情報
     */
    protected ChannelSftp connectChannelSftp(final Session session)
            throws JSchException {
        final ChannelSftp channel = (ChannelSftp) session.openChannel(CHANNEL_TYPE);
        try {
            channel.connect();
        } catch (JSchException e) {
            return null;
        }
        return channel;
    }


    /**
     * Session・Channelの終了
     *
     * @param session
     *            開始されたSession情報
     * @param channels
     *            開始されたChannel情報.複数指定可能
     */
    protected void disconnect(final Session session, final Channel... channels) {
        if (channels != null) {
            for (Channel c: channels ) {
                if (c != null) {
                    c.disconnect();
                }
            }
        }
        if (session != null) {
            session.disconnect();
        }
    }


    /**
     * SFTPに接続するユーザ情報を保持するクラス
     */
    private static class SftpUserInfo implements UserInfo {
        @Override
        public String getPassword() {
            return null;
        }
        @Override
        public boolean promptPassword(String arg0) {
            return true;
        }
        @Override
        public boolean promptPassphrase(String arg0) {
            return true;
        }
        @Override
        public boolean promptYesNo(String arg0) {
            return true;
        }
        @Override
        public void showMessage(String arg0) {
        }
        @Override
        public String getPassphrase() {
            return null;
        }
    }


    /**
     * ファイルアップロード
     *
     * @throws JSchException
     *             Session・Channelの設定/接続エラー時に発生
     */
    public void putFile(ChannelSftp channel, InputStream inStream, String destPath)
            throws SftpException {

        /*
         * sftp通信を実行
         */
        String absoluteDestPath = channel.getHome() + "/" + destPath;
        String destFile = new File(absoluteDestPath).getName();
        int numDestPath = absoluteDestPath.length();
        int numDestFile = destFile.length();
        String destParentPath = absoluteDestPath.substring( 0, numDestPath - numDestFile );
        channel.cd(destParentPath);
        channel.put( inStream, destFile);

        // confirm existance of destFile
        channel.lstat(destFile);
    }

    /*
     * サーバー上のファイルの削除
     *   destFileNameFront文字列から始まるファイルを全て削除する
    */
    public void deleteFiles(ChannelSftp channel, String destFileNameFront) throws SftpException {
        channel.rm(destFileNameFront + "*");
    }
}

SdCardDirPaths.java
package your.package;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Environment;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class SdCardDirPaths {

    /**
     * SDカードのfilesディレクトリパスのリストを取得する。
     * Android5.0以上対応。
     *
     * @param context
     * @return SDカードのfilesディレクトリパスのリスト
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public static List getSdCardFilesDirPathListForLollipop(Context context) {
        List sdCardFilesDirPathList = new ArrayList<>();

        // getExternalFilesDirsはAndroid4.4から利用できるAPI。
        // filesディレクトリのリストを取得できる。
        File[] dirArr = context.getExternalFilesDirs(null);


        for (File dir : dirArr) {
            if (dir != null) {
                String path = dir.getAbsolutePath();

                // isExternalStorageRemovableはAndroid5.0から利用できるAPI。
                // 取り外し可能かどうか(SDカードかどうか)を判定している。
                if (Environment.isExternalStorageRemovable(dir)) {

                    // 取り外し可能であればSDカード。
                    // このパスをパスリストに加える
                    if (!sdCardFilesDirPathList.contains(path)) {
                        sdCardFilesDirPathList.add(path);
                    }
                }
            }
        }
        return sdCardFilesDirPathList;
    }
}

(利用例)
Send2ServerTask.java
package your.package;

import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

// 複数のファイルをSSH送信する
public class Send2ServerTask extends AsyncTask {
    final String ServerIp = "SSH.SERVER.IP.ADDRESS";
    final int Port = 22;
    final String User = "SshLogInUser";
    final String IdentityKeyPath = "PRIVATE/KEY/FILE/PATH/IN/CLIENT/DEVICE";
    //     if IdentityKeyPath is illegal, password authentication is used.
    final String DestParentPath = "SERVER/DIR/TO/BE/STORED";

    private WeakReference weakRef;
    private HashMap inStreamMap;
    final private String passPhrase;
    final private String fileNameFront;
      // SSH失敗時のファイル削除のためにファイル名共通文字列を保持
      // 複数の送信ファイルはいずれもfileNameFront文字列で始まるファイル名とすること

    private Listener listener;

    /*
     * constructor
     *   inStreamMap 送信する複数ファイルのファイル名とインプットストリームをHashMapで渡す
     */
    Send2ServerTask(Activity parentActivity, HashMap inStreamMap,
                    String passPhrase, String fileNameFront) {
        weakRef = new WeakReference<>(parentActivity);
        this.inStreamMap = new HashMap<>(inStreamMap);
        this.passPhrase = passPhrase;
        this.fileNameFront = fileNameFront;
    }


    @Override
    protected String doInBackground(Void... params) {
        MyJsch mJsch;
        Session sftpSession = null;
        ChannelSftp sftpChannel = null;

        Activity refActivity = weakRef.get();
        if (refActivity == null || refActivity.isFinishing()) {
            return null;
        }

        Context appContext = weakRef.get().getApplicationContext();

        // initialise Jsch
        mJsch = new MyJsch(ServerIp, Port, User, passPhrase, IdentityKeyPath, appContext);

        // connect session, channel
        try {
            sftpSession = mJsch.connectSession();
            sftpChannel = mJsch.connectChannelSftp( sftpSession );

            // upload
            int count = 0;
            for ( Map.Entry entry : inStreamMap.entrySet()) {
                // entry.getKey()    entry.getValue()
                String destPath = DestParentPath + "/" + entry.getKey();
                try {
                    mJsch.putFile(sftpChannel, entry.getValue(), destPath);
                } catch (SftpException e) {
                    try {
                        // このセッションでアップロードされたファイルをすべて削除する
                        mJsch.deleteFiles(sftpChannel, fileNameFront);
                        mJsch.disconnect( sftpSession, sftpChannel);
                        return "Failed to upload files. count: " + count + ". " + destPath + " "  + e.toString();
                    } catch (SftpException e1) {
                        mJsch.disconnect( sftpSession, sftpChannel);
                        return "Failed to delete remote files. " + e1.toString();
                    }
                }

                try {
                    // take sleep between SFTP#puts
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // このセッションでアップロードされたファイルをすべて削除する
                    mJsch.deleteFiles(sftpChannel, fileNameFront);
                    mJsch.disconnect( sftpSession, sftpChannel);
                    return "Failed! sleep" + e.toString();
                }
                count++;
            }
            if ( count != inStreamMap.size()) {
                // このセッションでアップロードされたファイルをすべて削除する
                mJsch.deleteFiles(sftpChannel, fileNameFront);
                mJsch.disconnect( sftpSession, sftpChannel);
                return "Could not upload " + inStreamMap.size() + " files";
            }
        } catch (JSchException | SftpException e) {
            mJsch.disconnect( sftpSession, sftpChannel);
            return "connection failed. " + e.toString();

        } finally {
            // disconnect channel, session
            mJsch.disconnect( sftpSession, sftpChannel);
        }
        return "Succeeded. " + inStreamMap.size() + " files upload";
    }


    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        Activity refActivity = weakRef.get();
        if (refActivity == null || listener == null)  {
            Toast.makeText(refActivity, "failed sending to server.", Toast.LENGTH_LONG).show();
        } else {
            if ( result.contains("Succeeded") ) {
                Toast.makeText(refActivity, result, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(refActivity, result, Toast.LENGTH_LONG).show();
            }
            listener.onSuccess(result);
        }
        return;
    }

    void setListener(Listener listener) {
        this.listener = listener;
    }

    interface Listener {
        void onSuccess(String str);
    }
}

MyActivity.java
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_confirm_before_send);
        buttonOK = findViewById(R.id.buttonOK);
        setListeners();
    }

    /*
     * Send2ServerTaskへのリスナ
     *   サーバーへのアップロード終了後に行う処理を記述
     */
    private Send2ServerTask.Listener createListener() {
        return new Send2ServerTask.Listener() {
            @Override
            public void onSuccess(String result) {
                deleteFiles();
            }
        };
    }

    protected void setListeners(){
        buttonOK.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /*
                 * HashMap SSHサーバーに送るデータ
                 *   String 送信先ファイルパス
                 *   InputStream 送信ファイルのインプットストリーム
                 */
                HashMap dataMap = new HashMap<>();

                setData2dataMap(); // dataMapにSSH通信データをセットする
                setPassPhraseWord();
                setFileNameFront();

                /*
                 * dataMapを保管サーバーに送る
                 */
                send2serverTask = new Send2ServerTask(thisActivity, dataMap, passPhraseWord, fileNameFront);

                // Listenerを設定し、send2serverTaskを実行してdataMapを保管サーバーに送る
                send2serverTask.setListener(createListener());
                send2serverTask.execute();
            }
        });
    }

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]
package YOUR.PACKAGE.alertdialogsample;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity {

    Button button_dialog1, button_dialog2, button_dialog3;
    private TextView text_view;
    private FragmentManager flagmentManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        text_view = findViewById(R.id.text_view);
        button_dialog1 = findViewById(R.id.button_dialog1);
        button_dialog2 = findViewById(R.id.button_dialog2);
        button_dialog3 = findViewById(R.id.button_dialog3);


        // button_dialog1ボタンタップでAlertを表示させる
        button_dialog1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                flagmentManager = getSupportFragmentManager();

                // DialogFragment を継承したAlertDialogFragment1のインスタンス
                AlertDialogFragment1 dialogFragment = AlertDialogFragment1.newInstance(100);
                // DialogFragmentの表示
                dialogFragment.show(flagmentManager, "test alert dialog1");
            }
        });


        // button_dialog2ボタンタップでダイアログのメッセージを変えたAlertを表示させる
        //   newInstance()への引数を変更してメッセージを変える
        button_dialog2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                flagmentManager = getSupportFragmentManager();

                // DialogFragmentを継承したAlertDialogFragment2のインスタンス
                AlertDialogFragment1 dialogFragment = AlertDialogFragment1.newInstance(200);
                // DialogFragmentの表示
                dialogFragment.show(flagmentManager, "test alert dialog2");
            }
        });


        // button_dialog3ボタンタップでItemを選択するAlertを表示させる
        button_dialog3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                flagmentManager = getSupportFragmentManager();

                // DialogFragment を継承したAlertDialogFragmentのインスタンス
                AlertDialogFragment2 dialogFragment = new AlertDialogFragment2();
                // DialogFragmentの表示
                dialogFragment.show(flagmentManager, "test alert dialog");
            }
        });
    }


    public void setTextView(String message){
        text_view.setText(message);
    }


    /*
     * DialogFragmentを継承したクラスAlertDialogFragment1
     */
    public static class AlertDialogFragment1 extends DialogFragment {

        /*
         * コンストラクタを記述してはならない。
         * newInstance()でのsetArguments、onCreateDialog()でのgetArgumentsを利用する。
         */
        public static AlertDialogFragment1 newInstance( int requestCode) {
            AlertDialogFragment1 fragment = new AlertDialogFragment1();

            Bundle arguments = new Bundle();
            arguments.putInt("reqCode", requestCode);
            fragment.setArguments(arguments);

            return fragment;
        }

        @Override
        @NonNull
        public Dialog onCreateDialog(Bundle savedInstanceState) {

            int requestCode = getArguments().getInt("reqCode");

            AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());

            switch (requestCode) {
                case 100:
                    alert.setTitle("Test AlertDialog1");
                    alert.setMessage("Message is 100");
                    break;

                case 200:
                    alert.setTitle("Test AlertDialog2");
                    alert.setMessage("Message is 200");
                    break;

            }
            alert.setPositiveButton(R.string.dialog_ok, null);

            return alert.create();
        }
    }


    /*
     * DialogFragmentを継承したクラスAlertDialogFragment2
     */
    public static class AlertDialogFragment2 extends DialogFragment {
        // 選択肢のリスト
        private String[] menulist = {"選択(1)","選択(2)","選択(3)"};

        @Override
        @NonNull
        public Dialog onCreateDialog(Bundle savedInstanceState) {

            AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());

            alert.setTitle("Test AlertDialog3");
            alert.setItems(menulist, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int idx) {
                    // 選択1
                    if (idx == 0) {
                        setMassage(menulist[0]);
                    }
                    // 選択2
                    else if (idx == 1) {
                        setMassage(menulist[1]);
                    }
                    // 選択3, idx == 2
                    else{
                        setMassage(menulist[2]);
                    }
                }
            });
            return alert.create();
        }


        private void setMassage(String message) {
            MainActivity mainActivity = (MainActivity) getActivity();
            if (mainActivity != null) {
                mainActivity.setTextView(message);
            }
        }
    }
}

2019年5月26日日曜日

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

2019 May 26.




package YOUR.PACKAGE.APPLICATION;

/*
 * Re-use of https://akira-watson.com/android/file_search.html
 */

import android.os.Environment;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class SearchExternalStorageFile {

    // 外部ストレージ内のfileStrにマッチするファイルを検索
    public String[] searchFiles( String fileStr ){

        // マッチしたファイルの絶対パスを格納する
        List listMatchedFiles = new ArrayList<>();

        // String 型の ArrayList を生成
        List listDirectory = new ArrayList<>();

        // 外部ストレージのパスを取得する、パスは機種によって異なる
        File file = Environment.getExternalStorageDirectory();
        String storagePath = file.getPath();

        listDirectory.add(storagePath);

        int m = 0;
        int n = 0;
        String[] fileNames;
        String imgPath = null, fName;

        while(listDirectory.size() > m){

            File directory = new File(listDirectory.get(m));
            fileNames = directory.list();

            n = 0;
            while(fileNames.length > n){

                File subFile;
                subFile = new File(directory.getPath() + "/" + fileNames[n]);

                if (subFile.isDirectory()) {
                    listDirectory.add(directory.getPath() + "/" + fileNames[n]);

                } else {
                    if (fileNames[n].contains(fileStr)) {
                        listMatchedFiles.add(directory.getPath() + "/" + fileNames[n]);
                    }
                }
                n++;
            }
            m++;
        }
        int listSize = listMatchedFiles.size();
        return listMatchedFiles.toArray(new String[listSize]);
    }
}

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
package YOUR.PACKAGE;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    boolean is1stRun = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if ( is1stRun ) {
            // get text by dialog
            InputTextDialogFragment cdf = new InputTextDialogFragment();
            cdf.show(getSupportFragmentManager(),"dialog");
            is1stRun = false;
        }
    }


    public void onReturnValue(String value) {
        TextView textViewPhrase = (TextView)findViewById(R.id.textViewPhrase);
        textViewPhrase.setText(value);
    }

}

InputTextDialogFragment.java
package YOUR.PACKAGE;

import android.app.Dialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;

public class InputTextDialogFragment extends DialogFragment {
    EditText editTextPhrase;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = new Dialog(getActivity());
        dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
        dialog.setContentView(R.layout.input_text_dialog);

        editTextPhrase = (dialog.findViewById(R.id.editTextPhrase));

        dialog.findViewById(R.id.buttonOK).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String textPhrase = editTextPhrase.getText().toString();
                MainActivity callingActivity = (MainActivity) getActivity();
                callingActivity.onReturnValue(textPhrase);

                dismiss();
            }
        });

        return dialog;
    }
}

2019年5月3日金曜日

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

2019 May 03.


FirstActivity.java
(OnClickListener等は省略)


public class FirstActivity extends AppCompatActivity {
  Button button1 = (Button) findViewById(R.id.button1);
  button1.setEnabled(true);
  TextView textView1 = (TextView) findViewById(R.id.textView1);
  textView1.setText("start")

  new SecondTask(this).execute();
}

SecondTask.java
public class SecondTask extends AsyncTask {
  private WeakReference weakReference;

  /**
   * make WeakReference in constructor
   *   参照しているActivityを引数にしてWeakReferenceのインスタンスを生成する
  **/
  SecondTask(Context referenceContext) {
    private WeakReference weakReference;
    weakReference = new WeakReference<>(referenceContext);
  }

  /**
   * use of WeakReference in onPostExecute
   *   weakReference.get()で参照しているActivityのContextを取得し、それを通じてView を設定したりする
  **/
  @Override
  protected void onPostExecute(String result) {
    Activity activity = (Activity) weakReference.get();

    if (activity == null || activity.isFinishing()) return;

    activity.findViewById(R.id.button1).setEnabled(false);
    TextView tv = activity.findViewById(R.id.textView1);
    tv.setText("end");
  }
}

2019年5月2日木曜日

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

2019 May. 03.
2019 May. 02.

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




MainActivity.java

package YOUR.PACKAGE.NAME;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


    /** Channel接続タイプ */
    private static final String CHANNEL_TYPE = "sftp";

    private MyTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        /*
        final String ServerIP = "ServerIP";
        final int Port = PortNum;
        final String UserId = "USER";
        final String PassPhrase = "YOURPASSPHRASE";
        final String IdentityKeyPath = "YOUR/SECRET/FILE/PATH"; // Do not attach '/' at head of path
        final String SourcePath = "PATH/TO/SOURCE/FILE"; // Do not attach '/' at head of path
        final String DestPath = "PATH/TO/DEST/FILE";
        */

        final String ServerIP="";
        final int Port = ;
        final String UserId = "";
        final String PassPhrase = "";
        final String IdentityKeyPath = "";
        final String SourcePath = "";
        final String DestPath = "";

        Button button1= (Button) findViewById(R.id.button1);
        TextView textView1 = (TextView) findViewById(R.id.textView1);

        // タスクの生成
        task = new MyTask(ServerIP, Port, UserId, PassPhrase, IdentityKeyPath, SourcePath, DestPath,this);

        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.setEnabled(false);
                // 非同期処理を開始する
                task.execute();
            }
        });
    }
}


MyTask.java
package YOUR.PACKAGE.NAME;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.TextView;

import com.jcraft.jsch.JSchException;

import java.lang.ref.WeakReference;

public class MyTask extends AsyncTask {
    private final String ServerIp;
    private final int Port;
    private final String User;
    private final String IdentityKeyPath;
    private final String PassPhrase;
    private final String SrcPath;
    private final String DestPath;

    private WeakReference weakReference;


    // constructor
    MyTask(final String ServerIp, final int Port, final String User,
                  final String PassPhrase, final String IdentityKeyPath, final String SrcPath,
                  final String DestPath, Context referenceContext) {
        super();

        // 呼び出し元へのweakReference
        weakReference = new WeakReference<>(referenceContext);

        this.ServerIp = ServerIp;
        this.Port = Port;
        this.User = User;
        this.PassPhrase = PassPhrase;
        this.IdentityKeyPath = IdentityKeyPath;
        this.SrcPath = SrcPath;
        this.DestPath = DestPath;
    }



    /**
     * バックグランドで行う処理
     */
    @Override
    protected String doInBackground(Void... value) {
        // startJsch
        MyJsch mJsch = new MyJsch( ServerIp, Port, User, PassPhrase, IdentityKeyPath, SrcPath,
                DestPath, weakReference.get());
        try {
            mJsch.putFile();
        } catch (JSchException e) {
            e.printStackTrace();
            return e.toString();
        }
        return "Success";
    }


    /**
     * バックグランド処理が完了し、UIスレッドに反映する
     */
    @Override
    protected void onPostExecute(String result) {

        // get a reference to the activity if it is still there
        Activity activity = (Activity) weakReference.get();
        if (activity == null || activity.isFinishing()) return;

        activity.findViewById(R.id.button1).setEnabled(true);
        TextView tv = activity.findViewById(R.id.textView1);
        tv.setText(result);
    }

}


MyJsch.java
package YOUR.PACKAGE.NAME;
import android.content.Context;
import android.util.Log;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.UserInfo;

import java.io.File;
import java.util.Collections;
import java.util.List;

public class MyJsch {
    private final String ServerIp;
    private final int Port;
    private final String User;
    private final String PassPhrase;
    private final String IdentityKeyPath;
    private final String SrcPath;
    private final String DestPath;
    private Context activityContext;

    private String externalPath;

    /** Channel接続タイプ */
    private static final String CHANNEL_TYPE = "sftp";

    /**
     * コンストラクタ
     */
    MyJsch(final String ServerIp, final int Port, final String User, final String PassPhrase,
           final String IdentityKeyPath, final String SrcPath, final String DestPath,
           Context activityContext) {
        this.ServerIp = ServerIp;
        this.Port = Port;
        this.User = User;
        this.IdentityKeyPath = IdentityKeyPath;
        this.PassPhrase = PassPhrase;
        this.SrcPath = SrcPath;
        this.DestPath = DestPath;
        this.activityContext = activityContext;
    }


    /**
     * ファイルアップロード
     *
     * @throws JSchException
     *             Session・Channelの設定/接続エラー時に発生
     */
    public void putFile()
            throws JSchException {

        Session session = null;
        ChannelSftp channel = null;


        // 外部ストーリッジ確認
        List sdCardFilesDirPaths =
                SdCardDirPaths.getSdCardFilesDirPathListForLollipop( activityContext );
        Collections.sort(sdCardFilesDirPaths, new CompStringLength());
        for (String p : sdCardFilesDirPaths) {
            Log.d("My", "SDパスの1つ: " + p);
        }
        externalPath = sdCardFilesDirPaths.get(0);
        externalPath = externalPath.replaceAll("/Android.*$", "");
        Log.d("My", "SDパス: " + externalPath);

        // get sourcePath
        final String sourcePath = externalPath + "/" + SrcPath;
        Log.d("My", "sourcePath " + sourcePath );
        if ( new File(sourcePath).exists()) {
            Log.d("My", sourcePath + " exists.");
        } else {
            Log.d("My", sourcePath + " not exist.");
        }

        /*
         * sftp通信を実行
        */
        try {
            session = connectSession();
            channel = connectChannelSftp(session);

            String absoluteDestPath = channel.getHome() + "/" + DestPath;
            String destFile = new File(absoluteDestPath).getName();
            int numDestPath = absoluteDestPath.length();
            int numDestFile = destFile.length();
            String destParentPath = absoluteDestPath.substring( 0, numDestPath - numDestFile );

            Log.d("My", "absoluteDestPath is " + absoluteDestPath);
            Log.d("My", "destFile is " + destFile);
            Log.d("My", "destParentPath is " + destParentPath);
            Log.d("My", "current local directory is " + channel.lpwd());
            Log.d("My", "remote home directory is " + channel.getHome());

            channel.cd(destParentPath);
            channel.put(sourcePath, destFile);


            try {
                channel.lstat(destFile);
            } catch (SftpException e) {
                Log.d("My", DestPath + " does not exist.");
                Log.d("My", e.toString());
            }

        } catch (SftpException e) {
            Log.d("My",e.toString());
        } finally {
            disconnect(session, channel);
        }
    }

    /**
     * Sessionを開始
     */
    private Session connectSession()
            throws JSchException {

        final JSch jsch = new JSch();

        // 鍵追加
        String keyFilePath = externalPath + "/" + IdentityKeyPath;
        if ( new File(keyFilePath).exists()) {
            Log.d("My",  keyFilePath + " exists.");

        } else {
            Log.d("My",  keyFilePath + " not exist.");
        }

        jsch.addIdentity(keyFilePath, PassPhrase);

        // Session設定
        final Session session = jsch.getSession(User, ServerIp, Port);
        final UserInfo userInfo = new SftpUserInfo();

        // TODO 今回は使用しないがパスフレーズ等が必要な場合はUserInfoインスタンス経由で設定する

        session.setUserInfo(userInfo);

        session.connect();

        return session;
    }

    /**
     * SFTPのChannelを開始
     *
     * @param session
     *            開始されたSession情報
     */
    private ChannelSftp connectChannelSftp(final Session session)
            throws JSchException {
        final ChannelSftp channel = (ChannelSftp) session.openChannel(CHANNEL_TYPE);
        try {
            channel.connect();

        } catch (JSchException e) {
            Log.d("My",   e.toString());
        }
        return channel;
    }


    /**
     * Session・Channelの終了
     *
     * @param session
     *            開始されたSession情報
     * @param channels
     *            開始されたChannel情報.複数指定可能
     */
    private void disconnect(final Session session, final Channel... channels) {
        if (channels != null) {
            for (Channel c: channels ) {
                if (c != null) {
                    c.disconnect();
                }
            }
        }
        if (session != null) {
            session.disconnect();
        }
    }

    /**
     * SFTPに接続するユーザ情報を保持するクラス
     */
    private static class SftpUserInfo implements UserInfo {

        @Override
        public String getPassword() {
            return null;
        }

        @Override
        public boolean promptPassword(String arg0) {
            return true;
        }

        @Override
        public boolean promptPassphrase(String arg0) {
            return true;
        }

        @Override
        public boolean promptYesNo(String arg0) {
            return true;
        }

        @Override
        public void showMessage(String arg0) {
        }

        @Override
        public String getPassphrase() {
            return null;
        }
    }
}

2019年3月30日土曜日

android開発 assets内のファイルを外部ストレージに書き出す

2019 Mar. 30.

サンプル

// assets内のファイル名
private String fileName = "sample-image.jpg";

// 外部ストレージのパス
private String extFilePath;

extFilePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/" + fileName;


InputStream inputStream = getResources().getAssets().open(fileName);
// 外部ストレージのパスにファイルを保存
FileOutputStream output =new FileOutputStream(extFilePath)) {
    // バッファーを使って画像を書き出す
    int DEFAULT_BUFFER_SIZE = 10240 * 4;
    byte buf[]=new byte[DEFAULT_BUFFER_SIZE];
    int len;
    while((len=inputStream.read(buf)) != -1){
        output.write(buf,0,len);
    }
    output.flush();

2018年9月1日土曜日

android emulatorをqemu kvm で動かす

2018 Sep. 02.
2018 Sep. 01.

・# apt install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils virtinst cpu-checker

  インストール結果確認
   # kvm-ok
   INFO: /dev/kvm exists
   KVM acceleration can be used

・kvmグループにユーザーを追加する

・# chown USER:kvm /dev/kvm
 もしくは
 # chmod a+x /dev/kvm

2018年6月9日土曜日

android端末へのルーティング方式OpenVPNクライアントインストール

2019 Apr.  27.
2018 Sep. 30.
2018 Sep. 27.
2018 Jun. 09.

qiita.com/noraworld/items/2fe6be489e1d93c748b8 より

クライアント用秘密鍵の生成

サーバーにて
$ WORKDIR/easy-rsa/easyrsa3/easyrsa build-client-full CLIENTDEVNAME

VPN.ovpn を作る(ファイル名は任意だが、拡張子は .ovpn )

client

dev    tun
proto  udp

remote YOUR.GLOBAL.ADDRESS.HERE 1194

resolv-retry  infinite
nobind

persist-key
persist-tun

ca    ca.crt
cert  CLIENTDEVNAME.crt
key   CLIENTDEVNAME.key

comp-lzo
verb 3

persist-key, persist-tun, comp-lzo, verb はサーバ側と同じにする。サーバ側に設定してあればこちらにも入力し、設定していない場合は外す。

クライアント用ファイルを作業用ディレクトリに集約する


サーバーにて
$ mkdir WORK4CLIENT
$ cp VPN.ovpn WORK4CLIENT/
$ sudo cp /etc/openvpn/ca.crt WORK4CLIENT/
$ cp WORKDIR/easy-rsa/easyrsa3/pki/issued/CLIENTDEVNAME.crt WORK4CLIENT/
$ cp WORKDIR/easy-rsa/easyrsa3/pki/private/CLIENTDEVNAME.key WORK4CLIENT/
$ sudo chown YOU:YOURGROUP WORK4CLIENT/ca.crt
$ sudo chown YOU:YOURGROUP WORK4CLIENT/CLIENTDEVNAME.crt
$ sudo chown YOU:YOURGROUP WORK4CLIENT/CLIENTDEVNAME.key

android端末の適当なディレクトリに YOURWORKDIR/ の4ファイルををコピーする

android端末にOpenVPN for Androidをインストールする

OpenVPN for Androidを開き、「プロファイルの追加」アイコンをタップして、 .ovpnファイルをインポートし、他の3ファイルを読み込む。

OpenVPN for Android 設定

種別: 証明書
CA証明書 ca.crt
クライアント証明書  CLIENTDEVNAME.crt
クライアント証明書のキー CLIENTDEVNAME.key
ポート番号 1194
プロコトル UDP

TLS認証を使用する :  on
暗号化方式: AES-256-CBC


2018年5月30日水曜日

2018年4月12日木曜日

android端末 ASUS X00HDの不調時の起動


2018 Apr. 12.

起動しない時
 Volume Down と Power Switchを同時に10秒ほど押し続け、指を離すと、
 Droid君が現れるでもなく、起動した。

2018年1月21日日曜日

android Contextの取得

android Contextの取得

2018 Jan. 21.

HogeActivityのContextの取得

 AlertDialog.Builder(Context)でのContextの取得

  new AlertDialog.Builder(HogeActivity.this);

     getApplicationContext()ではエラーとなる。

2018年1月4日木曜日

androidプログラミング

androidプログラミング

2018 Jan. 06.
2018 Jan. 04.
2018 Jan. 03.
2017 Nov. 23.
2017 Aug. 16.

android, プログラミング, emulator, context, 1行, 読み込み,SD, ファイル読み込み, AlertDialog


preferenceで配列を扱う

https://qiita.com/ueno-yuhei/items/d51c00c5be3971f4cd40

コマンドラインからのemulator起動

$ Android/Sdk/tools/emulator -avd EMULATOR -qemu -m 512 -enable-kvm
EMULATOR: advの名前

context

参考サイト
http://yuki312.blogspot.jp/2012/02/thisgetapplicationcontextactivityapplic.html

1行読み込み


BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader(file));
} catch (FileNotFoundException e) {
    e.printStackTrace();
    if (br != null) try {
        br.close();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}

String str;
try {
    while((str = br.readLine()) != null){
        Log.v("Read",str);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (br != null) {
        try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

SDカード上のファイルの読み込み


private String filename = "hoge.txt";
private File directory = Environment.getExternalStorageDirectory();
private String filepath = directory.getAbsolutePath() + "/YourDir/" + filename;

private File file = new File(filepath);

// SDカードマウント状態

final String state = Environment.getExternalStorageState();

if (!state.equals(Environment.MEDIA_MOUNTED)) {

    try {
      throw new IOException("No Mount");
  } catch (IOException e) {
      e.printStackTrace();
  }
}

BufferedReader br = null;
try {
    br = new BufferedReader(new FileReader(file));
} catch (FileNotFoundException e) {
    e.printStackTrace();
    if (br != null) try {
        br.close();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}

String str;
try {
    while((str = br.readLine()) != null){
        Log.v("Read",str);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (br != null) {
        try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

AlertDialog setItems()利用時のコードと挙動



サンプル1 ダイアログにボタンを置かず、アイテムをクリックすれば前画面に戻る

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final Button btn = (Button)findViewById(R.id.btn);
    btn.setText("Show Dialog");
    btn.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        final CharSequence[] items = {"car", "train", "byke"};
        new AlertDialog.Builder(MainActivity.this)
          .setTitle("Select tool")
          .setIcon(R.drawable.myIcon)
          .setItems(items, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dlg, int which) {
              btn.setText(String.format("%sが選択されました。",items[which]));
            }
          })
          .show();
      }
    });
  }
}

サンプル2 ダイアログにボタンを置かず、アイテムをクリックしても前画面に戻らない

public class MainActivity extends Activity implements DialogInterface.OnClickListener {
    final String[] items = {"car", "train", "byke"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button btn = (Button)findViewById(R.id.btn);
        btn.setText("Show Dialog");
        btn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                myShowDialog("Not Selected");
            }
        });
    }

    @Override
    public void onClick(DialogInterface dlg, int which) {
        myShowDialog(items[which]);
    }

    public void myShowDialog(final String titleStr) {
        AlertDialog.Builder dialog = new AlertDialog.Builder(this);
        dialog.setTitle(titleStr);
        dialog.setIcon(R.drawable.myIcon);
        dialog.setItems(items, this);
        dialog.show();
    }
}

サンプル3 ダイアログにボタンを置くが、アイテムのクリックでは前画面に戻らない

public class MainActivity extends Activity implements DialogInterface.OnClickListener {
    TextView tv;
    final String[] items = {"car", "train", "byke"};
    final List listItems = Arrays.asList(items); //配列をList型オブジェクトに変換

    @Override
    public void onClick(DialogInterface dlg, int which) {
        Log.v("dialog_which", String.valueOf(which)); // int of order of items
        showDialog(items[which]);
    }

    public void showDialog(final String titleStr) {
        AlertDialog.Builder dialog = new AlertDialog.Builder(this);
        dialog.setTitle(titleStr);
        dialog.setIcon(R.drawable.myIcon);
        dialog.setItems(items, this);

        dialog.setPositiveButton("決 定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int index) {
                Log.v("dialog_index", String.valueOf(index));  // unexpected int
                tv.setText(titleStr);
            }
        });

        dialog.setNeutralButton("前 へ", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int index) {
                Log.v("dialog_index", String.valueOf(index)); // unexpected int
                int i = listItems.indexOf(titleStr); //list内に引数の要素が存在する最小のインデックスを返す
                int numArray = (i+3-1)%3;
                tv.setText(items[numArray]);
            }
        });

        dialog.setNegativeButton("2つ前へ", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int index) {
                Log.v("dialog_index", String.valueOf(index));  // unexpected int
                int i = listItems.indexOf(titleStr); //list内に引数の要素が存在する最小のインデックスを返す
                int numArray = (i+3-2)%3;
                tv.setText(items[numArray]);
            }
        });
        dialog.show();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = ((TextView)findViewById(R.id.tv));
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                showDialog("");
            }
        });
    }
}