Honeycombチュートリアル その4

ActionModeの設定

===============================
イメージ長押しでActionModeを設定する

完成図

手順

  1. string.xmlの変更
    1. add photo_selection_cab_title
  2. ActionModeのためのメニューを作成する
    1. menuレイアウトの作成
      1. photo_context_menu.xml
  3. ContentFragmentの修正
    1. フィールドの追加
      1. private ActionMode currentActionMode;
      2. private ActionMode.Callback mContentSelectionActionModeCallback
    2. ActionMode.Callbakの作成
      1. onPrepareActionMode
      2. onCreateActionMode
    3. onCreateViewメソッドの修正
      1. setOnLongClickListenreの追加
ActionModeとは

アクションモードは、コンテンツをモーダルインタラクションのために使用され、終了するまで、通常のUIの部分を置き換えることができます。

string.xml
                                • -
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">HoneycomicGallery</string>
        <string name="photo_selection_cab_title">Photo selection</string>
    </resources>
photo_context_menu.xml
                                                    • -
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:title="Share" android:icon="?attr/menuIconShare" android:id="@+id/share" android:showAsAction="always|withText"></item>
    </menu>
ContentFragment.java
                                                    • -

フィールドの追加
現在のアクションモードとActionModeのコールバックを生成

private ActionMode currentActionMode;
private ActionMode.Callback mContentSelectionActionModeCallback
ActionMode.Callback の作成

ActionModeのためのコールバックインタフェース
アクションモードとユーザーの相互作用によって発生したイベントを処理します。

  • onCreateActionMode(ActionMode, Menu)
    • 最初に作成された時だけ呼ばれる
  • onPrepareActionMode(ActionMode, Menu)
    • 作成後とActionModeになる直前と無効化時に、アクションモードのアクションメニューをリフレッシュするために呼び出されます。
  • onActionItemClicked(ActionMode, MenuItem)
    • Actionボタンを押した時
  • onDestroyActionMode(ActionMode)
    • AnctionModeを終了するとき
	private ActionMode.Callback contentSelectionActionCallback = new ActionMode.Callback() {
		
		@Override
		public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
			return false;
		}
		
		@Override
		public void onDestroyActionMode(ActionMode mode) {
			contentView.setSelected(false);
			currentActionMode = null;
		}
		
		@Override
		public boolean onCreateActionMode(ActionMode mode, Menu menu) {
			mode.setTitle(R.string.photo_selection_cab_title);
			
			MenuInflater inflater = getActivity().getMenuInflater();
			inflater.inflate(R.menu.photo_context_menu, menu);
			return true;
		}
		
		@Override
		public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
			switch (item.getItemId()) {
			case R.id.share:
				shareCurrentPhoto();
				mode.finish();
				return true;
			}
			return false;
		}
	};
ロングクリック時の処理

contentViewにOnLongClickListenterの実装
ロングクリック時にActionModeを開始する

  • public ActionMode startActionMode (ActionMode.Callback callback)
    • ActionModeを開始する
    • 引数にActionModeイベントのコールバックリスナを設定する
             // When long-pressing a photo, activate the action mode for selection, showing the
             // contextual action bar (CAB).
                     contentView.setOnLongClickListener(new OnLongClickListener() {

                             @Override
                             public boolean onLongClick(View v) {
                                     if(currentActionMode != null){
                                             return false;
                                     }
                                     currentActionMode = getActivity().startActionMode(contentSelectionActionCallback);
                                     contentView.setSelected(true);
                                     return true;
                             }
                     });

                     // TODO change image resource. this operation will be deleted later.
                     bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.big_droid);
                     imageView.setImageBitmap(bitmap);

                     return contentView;
             }
実行結果
                            • -

long-press a photo

オプションメニューを選択した時の設定

=============================================
選択した画像をシェアする

  • create method
    • void shareCurrentPhoto()
    • create AsyncTask that inner class into the shareCurrentPhoto method.

  • change onActionItemClicked method
    • call of share proccess.
  • change AndroidManifest.xml
    • add uses-permission
      • android.permission.WRITE_EXTERNAL_STORAGE
ContentFragment.java
                                                        • -
	package com.hidecheck.honeycomic;
	
	import java.io.File;
	import java.io.FileNotFoundException;
	import java.io.FileOutputStream;
	import java.io.IOException;
	
	import android.app.ActionBar;
	import android.app.Activity;
	import android.app.Fragment;
	import android.content.Intent;
	import android.graphics.Bitmap;
	import android.graphics.BitmapFactory;
	import android.net.Uri;
	import android.os.AsyncTask;
	import android.os.Bundle;
	import android.util.Log;
	import android.view.ActionMode;
	import android.view.LayoutInflater;
	import android.view.Menu;
	import android.view.MenuInflater;
	import android.view.MenuItem;
	import android.view.View;
	import android.view.View.OnClickListener;
	import android.view.View.OnLongClickListener;
	import android.view.View.OnSystemUiVisibilityChangeListener;
	import android.view.ViewGroup;
	import android.widget.ImageView;
	import android.widget.Toast;
	
	public class ContentFragment extends Fragment {
		private View contentView;
		
		// The bitmap currently used by ImageView
		private Bitmap bitmap = null;
	
		// Current action mode (contextual action bar, a.k.a. CAB)
		private ActionMode currentActionMode;
	
	    
		@Override
		public void onActivityCreated(Bundle savedInstanceState) {
			super.onActivityCreated(savedInstanceState);
		}
	
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
			contentView = inflater.inflate(R.layout.content_wellcome, null);
			final ImageView imageView  = (ImageView)contentView.findViewById(R.id.image);
			contentView.setDrawingCacheEnabled(false);
	
			// TODO setting DragListener later
			
	        // Keep the action bar visibility in sync with the system status bar. That is, when entering
	        // 'lights out mode,' hide the action bar, and when exiting this mode, show the action bar.
			final Activity activity = getActivity();
			contentView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
				
				@Override
				public void onSystemUiVisibilityChange(int visibility) {
					ActionBar actionBar = activity.getActionBar();
					if(actionBar != null){
						contentView.setSystemUiVisibility(visibility);
						if(visibility == View.STATUS_BAR_VISIBLE){
							actionBar.show();
						}else{
							actionBar.hide();
						}
					}
				}
			});
	
			contentView.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					if(contentView.getSystemUiVisibility() == View.STATUS_BAR_VISIBLE){
						contentView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
					}else{
						contentView.setSystemUiVisibility(View.STATUS_BAR_VISIBLE);
					}
				}
			});
			
	        // When long-pressing a photo, activate the action mode for selection, showing the
	        // contextual action bar (CAB).
			contentView.setOnLongClickListener(new OnLongClickListener() {
				
				@Override
				public boolean onLongClick(View v) {
					if(currentActionMode != null){
						return false;
					}
					currentActionMode = getActivity().startActionMode(contentSelectionActionCallback);
					contentView.setSelected(true);
					return true;
				}
			});
			
			// TODO change image resource. this operation will be deleted later.
			bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.big_droid);
			imageView.setImageBitmap(bitmap);
	
			return contentView;
		}
		
		void shareCurrentPhoto() {
			File externalCacheDir = getActivity().getExternalCacheDir();
			if(externalCacheDir == null){
				Toast.makeText(getActivity(), "Error writing to USB/external storage.", Toast.LENGTH_SHORT).show();
				return;
			}
			
			// Prevent media scanning of the cache directory.
			final File noMediaFile = new File(externalCacheDir, ".nomedia");
			try{
				noMediaFile.createNewFile();
			}catch (IOException e) {
				Log.e(getClass().getName(), "shareCurrentPhoto", e);
			}
			
	        // Write the bitmap to temporary storage in the external storage directory (e.g. SD card).
	        // We perform the actual disk write operations on a separate thread using the
	        // {@link AsyncTask} class, thus avoiding the possibility of stalling the main (UI) thread.
	
	        final File tempFile = new File(externalCacheDir, "tempfile.jpg");
	
	        new AsyncTask<Void, Void, Boolean>(){
	
	            /**
	             * Compress and write the bitmap to disk on a separate thread.
	             * @return TRUE if the write was successful, FALSE otherwise.
	             */
				@Override
				protected Boolean doInBackground(Void... params) {
					
					try{
						FileOutputStream fo = new FileOutputStream(tempFile, false);
						if(!bitmap.compress(Bitmap.CompressFormat.JPEG, 60, fo)){
							Toast.makeText(getActivity(), "Error writing bitmap data.", Toast.LENGTH_SHORT).show();
							return Boolean.FALSE;
						}
						return Boolean.TRUE;
					}catch (FileNotFoundException e) {
						Toast.makeText(getActivity(), "Error writing to USB/external storage.", Toast.LENGTH_SHORT).show();
						return Boolean.FALSE;
					}
				}
	
	            /**
	             * After doInBackground completes (either successfully or in failure), we invoke an
	             * intent to share the photo. This code is run on the main (UI) thread.
	             */
				@Override
				protected void onPostExecute(Boolean result) {
					if(result != Boolean.TRUE){
						return;
					}
					
					Intent shareIntent = new Intent(Intent.ACTION_SEND);
					shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile));
					shareIntent.setType("image/jpeg");
					startActivity(Intent.createChooser(shareIntent, "Share photo"));
				}
	        }.execute();
		}
		
		private ActionMode.Callback contentSelectionActionCallback = new ActionMode.Callback() {
			
			@Override
			public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
				return false;
			}
			
			@Override
			public void onDestroyActionMode(ActionMode mode) {
				contentView.setSelected(false);
				currentActionMode = null;
			}
			
			@Override
			public boolean onCreateActionMode(ActionMode mode, Menu menu) {
				mode.setTitle(R.string.photo_selection_cab_title);
				
				MenuInflater inflater = getActivity().getMenuInflater();
				inflater.inflate(R.menu.photo_context_menu, menu);
				return true;
			}
			
			@Override
			public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
				switch (item.getItemId()) {
				case R.id.share:
					shareCurrentPhoto();
					mode.finish();
					return true;
				}
				return false;
			}
		};
	}
AndroidManifest.xml
                                          • -

sdcardの書き込みを有効にする

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
実行結果
                            • -

after click a "Share".

↓ clicked