サンプルプログラム工場

AAKAKA Appで使われているプログラムのサンプルコードをそのまま公開!

サンプルプログラム工場 > android > [Android]eml形式で保存したメール(SPモードメール)を表示するサンプル#tryShowEMLFile00
Google Play AAKAKAxSOFTへ

[Android]eml形式で保存したメール(SPモードメール)を表示するサンプル#tryShowEMLFile00

実行ファイル(APK)やサンプル(zip)をダウンロードする
tryShowEMLFile00の実行イメージtryShowEMLFile00の実行イメージ

eml形式で保存したメールを表示する。
HTML形式のメールがあるので、画像を含めて表示できる様にする。
javaxを使うにはGoogleが出しているAndroid版のやつをDLしてプロジェクトに組み込まないとだめみたい。
activation.jar,additionnal.jar, mail.jarをダウンロードしてきてlibsフォルダに入れる。
メールを送信したい場合は↓パーミッションの設定をしないといけないけど、今回は解析だけなので指定はしない。
android.permission.INTERNET
android.permission.ACCESS_NETWORK_STATE
テンポラリをつかって画像を扱うならパーミッションはいらないけど、それ以外のフォルダに保存する場合は↓パーミッションの指定がいる。
android.permission.WRITE_EXTERNAL_STORAGE

検索した事
 Javax android
 MimeMessage java
 java html mail parser
 javamail Multipart
 BodyPart.INLINE
javamail BodyPart contentid
 android WebView
 Android テンポラリファイル

開発環境
 Eclipse IDE バージョン: 3.7 Indigo Service Release 2
 ターゲットプラットフォーム: 2.1
 API レベル: 7

package sample.example.tryshowemlfile00;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Stack;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.*;

import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
import android.util.Xml.Encoding;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebView;
import android.widget.EditText;
import android.support.v4.app.NavUtils;

public class tryShowEMLFile00Activity extends Activity implements FileOpenDialogListener {
	
	private EditText mEditText;	// 結果を表示するためのエディットテキスト
	private WebView mWebView;	// WebView

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_try_show_emlfile00);

        // 結果を表示するためのエディットテキスト
		this.mEditText = (EditText)this.findViewById(R.id.editText1);
		this.mEditText.setText("ここにソースが表示される。");
		
		// メールの内容を表示するためのWebView
		this.mWebView = (WebView)this.findViewById(R.id.webView1);
		// ↓この引数のやつ以外はバグって使えねぇ
		this.mWebView.loadDataWithBaseURL("about:blank","<html><body>ここにHTMLで表示される</body></html>", "text/html", "UTF-8",null); 
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_try_show_emlfile00, menu);
        return true;
    }

    /**
     * ファイルが選択された
     */
	public void onFileSelected(File file) {
		this.mEditText.setText(file.getAbsolutePath());
		this.showDML(file.getAbsolutePath());
	}
	
	
    /**
     * ボタンがクリックされたときの処理(Buttonの「On Click」プロパティに設定すると呼ばれる)
     * @param view なんかのビューだけど使わない
     */
    public void onClickButton1(View view) {
    	// ファイル選択
        FileOpenDialog fod = new FileOpenDialog(this, this, false);

        // DOCOMOの場合は↓にデフォルトでEMLファイルがエクスポートされる
        // /sdcard/private/docomo/mail/export/
        fod.openDirectory("/sdcard/");
    }

    // 画像ののパスリスト
    //private Map<String, File> mImgList = new HashMap<String, File>();
    
    // 画像ののキーのリスト
    private List<String> mImgKeyList = new ArrayList<String>();	// CIDのIMG
    private List<File> mImgFileList = new ArrayList<File>();	// イメージファイルのパス
    
    /**
     * DMLファイルを表示する
     * @param path DMLファイルのパス
     */
    private void showDML(String path) {
    
    	// イメージリストをクリアする
    	//this.mImgList.clear();
    	this.mImgFileList.clear();
    	this.mImgKeyList.clear();
    	
    	Properties props = System.getProperties();
    	props.put("mail.host", "smtp.gmail.com");
    	props.put("mail.transport.protocol", "smtp");
    	
    	Session mailSession = Session.getDefaultInstance(props, null);
    	InputStream source = null;
		try {

			source = new FileInputStream(path);
			MimeMessage message = null;
			message = new MimeMessage(mailSession, source);
			
			String[] date = message.getHeader("Date");
    	
			String res = "";
			res = "件名:" + message.getSubject() + "\n";
	    	res += "差出人:" + message.getFrom()[0] + "\n";
	    	res += "受信日時:" + date[0] + "\n\n";

	    	String code = "";
	    	
	    	// 平文(HTMLじゃなしに普通のテキスト)
			if (Pattern.compile(Pattern.quote("text/plain"),
					Pattern.CASE_INSENSITIVE).matcher(
							message.getContentType()).find()) {
				String content = (String)message.getContent();
				// そのままメッセージになってる
				res += content;
				
				// コードの方にも表示
				content = content.replace("\n", "<br />");
				code = "<html><body><div style=\"font-size: 14px;\">" + content + "</div></body></html>";
				
			// 多分HTML(画像とか抜き出してやる必要がある)
			} else {
				Multipart multiPart = (Multipart)message.getContent();
				
				// Multipartを読み込む(この中にHTML入ってる)
				code = this.readMultipart(multiPart);
		    	
		    	// コードに画像を埋め込む
		    	for (int i = 0; i < this.mImgKeyList.size(); i++) {
		    		String key = this.mImgKeyList.get(i);
		    		String imgPath = this.mImgFileList.get(i).getName();//this.mImgList.get(this.mImgKeyList.get(i)).getName();
		    		code = code.replace(key, imgPath);
		    	}
		    	res += code;
			}
			
			// 編集が終わった文字列をそのまま表示
	    	this.mEditText.setText(res);
	    	
	    	
			// ↓この引数のやつ以外はバグってなにか変なことになるらしい
			//this.mWebView.loadDataWithBaseURL("about:blank", code, "text/html", "UTF-8", null);
	    	// ローカルのやつを指定するときは先頭に"file:"ってつける。
	    	// 最後に"/"で閉じるのを忘れずに!
	    	// ベースのディレクトリを指定すると、そこからの相対パスが使える
	    	String baseDir = "file:" + this.getCacheDir().getAbsolutePath() + "/";
	    	this.mWebView.loadDataWithBaseURL(baseDir, code, "text/html", "UTF-8", null);


		} catch (MessagingException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}

    }
    
    /**
     * MultipartからHTMLや画像データを読み込む
     * @param mp いろいろごちゃっと中に入ってるやつ
     * @return 読み込んだHTMLコード
     * @throws MessagingException
     * @throws IOException
     */
    public String readMultipart(Multipart mp) throws MessagingException, IOException {
    	String res = "";
    	
    	// 全部のパーツを順番にチェック、チャンク的な
    	for (int i = 0; i < mp.getCount(); i++) {
			BodyPart bodyPart = mp.getBodyPart(i);
			
			// HTML要素
			if (Pattern.compile(
					Pattern.quote("text/html"),
					Pattern.CASE_INSENSITIVE).matcher(
							bodyPart.getContentType()).find()) {
				// HTMLパーツが見つかった!
				res += bodyPart.getContent() + "\n";
				
			// ここはテキストそのまま。
			// 必要な場合はこっちから取り出す
			} else if (Pattern.compile(
					Pattern.quote("text/plain"),
					Pattern.CASE_INSENSITIVE).matcher(
							bodyPart.getContentType()).find()) {
				res += (String)bodyPart.getContent();
			// 次の階層にイメージやらHTMLやらが入ってるよ
			} else if (Pattern.compile(
					Pattern.quote("multipart/alternative"),
					Pattern.CASE_INSENSITIVE).matcher(
							bodyPart.getContentType()).find()) {
				// ネストしてるから次の階層へ
				res += this.readMultipart((Multipart)bodyPart.getContent()) + "\n";
			
			// 次の階層にイメージやらHTMLやらが入ってるよ
			} else if (Pattern.compile(
					Pattern.quote("multipart/related"),
					Pattern.CASE_INSENSITIVE).matcher(
							bodyPart.getContentType()).find()) {
				// ネストしてるから次の階層へ
				res += this.readMultipart((Multipart)bodyPart.getContent()) + "\n";
			// 画像(gifやjpegやら)
			} else if (Pattern.compile(
					Pattern.quote("Image/"),
					Pattern.CASE_INSENSITIVE).matcher(
							bodyPart.getContentType()).find()) {
				
				// 画像ファイル名を取り出す
				String filename = bodyPart.getFileName();
				//res += "IMAGE:" + header[0] + " -> " + filename + "\n";
				
				// コンテンツIDで画像とHTMLコードをつなぐのでコンテンツIDを取っておく
				String header[] = bodyPart.getHeader("Content-Id");
				// "cid:01@xxxxxx.xxxxxx"みたいな形に直す
				String cid = "cid:" + header[0].substring(1, header[0].length() - 1);
				
				// イメージのSRC要素に入ってるコンテンツIDをセット
				this.mImgKeyList.add(cid);
				
				// SRCのキーとファイルのパスを関連づける
				this.mImgFileList.add(this.putImageFile(bodyPart));
			} else {
				// 他は別に今回はいいんだ。
			}
		}
    	return res;
    }
    
    /**
     * 画像ファイルをテンポラリに書き出す
     * @param bodyPart imageのBodyPart
     * @return 描き出したファイルの情報
     * @throws IOException
     * @throws MessagingException
     */
    private File putImageFile(BodyPart bodyPart) throws IOException, MessagingException {
    	// イメージのストリームを取り出す
		InputStream is = bodyPart.getInputStream();

		// キャッシュディレクトリに対してファイルを書き出す
    	File outDir = this.getCacheDir();
    	//File outFile = new File("/sdcard/___POOL/" + random.nextInt() + ".gif");//File.createTempFile("tmp", ".gif", outDir);
    	//outFile.createNewFile();
    	// テンポラリファイルを作る
    	File outFile = File.createTempFile("tmp", ".img", outDir);
    	OutputStream os = new FileOutputStream(outFile);

    	// テンポラリファイルに対してイメージを描き出す
    	byte buffer[] = new byte[256];
    	int len = 0;
    	while((len = is.read(buffer)) != -1) {
    		os.write(buffer, 0, len);
    	}
    	
    	// ストリームを閉じる
    	os.flush();
    	os.close();
    	is.close();
    	
    	return outFile;
    }
}



/**
 * 選択されたときに呼び出されるリスナー
 *
 */
interface FileOpenDialogListener {
	void onFileSelected(final File file);
}

/**
 * ファイルが選択されたダイアログ
 *
 */
class FileOpenDialog implements DialogInterface.OnClickListener {

	private Context mParent = null;	// 親のコンテキスト
	private int mSelectedItemIndex = -1;	// 選択中のアイテムインデックス
	private File[] mFileList;	// 表示中のファイルのリスト
	
	private String mCurrDirectory = null;	// 今居るディレクトリ
	private Stack<String> mDirectorys = new Stack<String>();	// ディレクトリ
	
	private FileOpenDialogListener mListener;	// リスナー
	
	private boolean mOpenDirectory;	// ディレクトリを開く
	private File mLastSelectedItem;	// 最後に選択されたモノ

	/**
	 * コンストラクタ
	 * @param parent 親のコンテキスト
	 * @param listener 選択が決まったときに呼び出される
	 * @param openDirectory true:ディレクトリを開く
	 */
	public FileOpenDialog(final Context parent, final FileOpenDialogListener listener, boolean openDirectory) {
		super();
		
		// コンテキスト
		this.mParent = parent;
		
		// リスナー
		this.mListener = listener;
		
		// ディレクトリだけを開くか
		this.mOpenDirectory = openDirectory; 
	}

	/**
	 * ダイアログが選択されたときに呼び出される
	 */
	public void onClick(DialogInterface dialog, int which) {
		
		// 今の選択されているモノ
		this.mSelectedItemIndex = which;

		// ファイルリストが空じゃない
		if (this.mFileList != null) {
			
			int selectedItemIndex = this.mSelectedItemIndex;	// 選択されている項目
			
			// 上の階層がある場合
			if (0 < this.mDirectorys.size()) {
				// 上の階層ボタン分減らす
				selectedItemIndex--;
			}

			// 上の階層へが選択されてた
			if (selectedItemIndex < 0) {
				
				// 一つ上の階層へ移動する
				this.openDirectory(this.mDirectorys.pop());
			
			} else {
				
				// ファイルを取り出す
				this.mLastSelectedItem = this.mFileList[selectedItemIndex];
				// ディレクトリの場合はそのディレクトリのモノを表示する
				if (this.mLastSelectedItem.isDirectory()) {
					
					// 次の階層に移動する前に、今の階層に戻れる様にスタックに積んでおく
					this.mDirectorys.push(this.mCurrDirectory);
					
					// 次の階層で新しくダイアログを開く
					this.openDirectory(this.mLastSelectedItem.getAbsolutePath());
				
				// ファイルだった場合は、そのファイルを選択されたファイルとして登録する
				} else {
					// ファイルが選択されたことを通知する
					this.mListener.onFileSelected(this.mLastSelectedItem);
				}
			}
		}
	}
	
	/**
	 * 指定のディレクトリを開く
	 * @param dir 開きたいディレクトリ(このディレクトリがルートディレクトリになる)
	 */
	public void openDirectory(String dir) {
		try {
			// ディレクトリだけ取り出したい
			if (this.mOpenDirectory == true) {
				
				// ディレクトリだけ取り出す(フィルタ使う)
				this.mFileList = new File(dir).listFiles(new FileFilter() {
					public boolean accept(File pathname) {
						// ディレクトリだけ許可
						if (pathname.isDirectory())
							return true;
						return false;
					}
				});
				
			} else {
				
				// 指定のディレクトリのファイルを全部取り出す
				this.mFileList = new File(dir).listFiles();
			}
			
			// 今の階層を取っておく
			this.mCurrDirectory = dir;
			
			// 何もとれなかった(開けない階層、多分アクセス権限がない)
			if (this.mFileList == null) {
				// 一つ上の階層へ移動する
				this.openDirectory(this.mDirectorys.pop());
				return ;
			}

			// 何も残ってない(ディレクトリが確定)
			if (this.mFileList.length <= 0) {
				this.mListener.onFileSelected(this.mLastSelectedItem);
				return ;
			}
			
			// Alertダイアログのために配列を用意する
			String[] fileNameList = null;
			int itemCount = 0;
			
			// ルートディレクトリ以外
			if (0 < this.mDirectorys.size()) {
				// 上の階層へ行くための項目を追加する
				fileNameList = new String[this.mFileList.length + 1];
				fileNameList[itemCount] = "<上の階層>";
				itemCount++;
				
			// ルートディレクトリ
			} else {
				// ファイルの数だけ
				fileNameList = new String[this.mFileList.length];
			}
			
			// 見つかったファイルの分だけ追加する
			for (File currFile : this.mFileList) {
				
				// ディレクトリだった
				if (currFile.isDirectory()) {
					// 最後に/を加えてディレクトリの表示を
					fileNameList[itemCount] = currFile.getName() + "/";
					
				// ファイルだった
				} else {
					fileNameList[itemCount] = currFile.getName();
				}
				itemCount++;
			}
			
			// ダイアログを表示する
			new AlertDialog.Builder(this.mParent)
				.setTitle(dir)
				.setItems(fileNameList, this)
				.show();
			
		} catch (SecurityException se) {
			Log.e("SecurityException", se.getMessage());
		} catch (Exception e) {
			Log.e("Exception", e.getMessage());
		}
	}

}
APKファイルをダウンロード サンプルプロジェクトをダウンロード

, , , , , , ,

[Android]ファイル/フォルダ選択ダイアログのサンプル#tryFileOpenDialog00 [C#|CSharp]小さなコード

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>