/** * Copyright (C) 2013 Samsung Electronics Co., Ltd. All rights reserved. * * Mobile Communication Division, * Digital Media & Communications Business, Samsung Electronics Co., Ltd. * * This software and its documentation are confidential and proprietary * information of Samsung Electronics Co., Ltd. No part of the software and * documents may be copied, reproduced, transmitted, translated, or reduced to * any electronic medium or machine-readable form without the prior written * consent of Samsung Electronics. * * Samsung Electronics makes no representations with respect to the contents, * and assumes no responsibility for any errors that might appear in the * software and documents. This publication and the contents hereof are subject * to change without notice. */ package com.samsung.chord.samples.apidemo; import java.util.ArrayList; import java.util.HashMap; import java.util.Random; import android.app.Activity; import android.app.AlertDialog; import android.app.Fragment; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.util.Log; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import com.samsung.chord.samples.apidemo.adapter.ChatListAdapter; import com.samsung.chord.samples.apidemo.adapter.ChatListAdapter.ICancelFileButtonListener; import com.samsung.chord.samples.apidemo.adapter.NodeListAdapter; import com.samsung.chord.samples.apidemo.service.ChordApiDemoService; import com.samsung.chord.samples.apidemo.service.ChordApiDemoService.IChordServiceListener; import com.samsunghack.apps.android.noq.IncomingMessageInterstitial; import com.samsunghack.apps.android.noq.IncomingMessageView; import com.samsunghack.apps.android.noq.R; public class DataTestFragment extends Fragment implements OnClickListener, OnScrollListener, OnItemClickListener, ICancelFileButtonListener { private static final String TAG = "[Chord][ApiTest]"; private static final String TAGClass = "DataTestFragment : "; private static final int GET_CONTENTS = 101; private ChordApiDemoService mChordService = null; private TextView mMyNodeNameTextView, mMyIpAddressTextView, mNewMessageTextView, mPublicNewMessageTextView, mChannelNameTextView; private ListView mNodeListView, mChatListView, mPublicNodeListView, mPublicChatListView; private EditText mInputEditText; private Button mFileSelectButton; private NodeListAdapter mNodeListAdapter; private ChatListAdapter mChatListAdapter; private NodeListAdapter mPublicNodeListAdapter; private ChatListAdapter mPublicChatListAdapter; private String mChannelType = ""; private String mMyNodeName; private HashMap<String, AlertDialog> mAlertDialogMap = null; OnChordMessageReceive mCallback; // Container Activity must implement this interface public interface OnChordMessageReceive { public void onChordMessageReceive(String message); } private GestureDetector mGesture = new GestureDetector(getActivity(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { Log.d(TAG + TAGClass, "****** onDoubleTap ******"); return true; } }); public DataTestFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.datatest_fragment, null); mChannelNameTextView = (TextView)view.findViewById(R.id.datatest_channelname_texttview); mMyNodeNameTextView = (TextView)view.findViewById(R.id.datatest_myname_texttview); mMyIpAddressTextView = (TextView)view.findViewById(R.id.datatest_myipaddress_textView); mNewMessageTextView = (TextView)view.findViewById(R.id.datatest_newmessage_textview); mNewMessageTextView.setText(""); mNewMessageTextView.setOnClickListener(this); mPublicNewMessageTextView = (TextView)view .findViewById(R.id.datatest_public_newmessage_textview); mPublicNewMessageTextView.setOnClickListener(this); mPublicNewMessageTextView.setText(""); mNodeListView = (ListView)view.findViewById(R.id.datatest_nodelist_listview); mChatListView = (ListView)view.findViewById(R.id.datatest_chat_listview); mPublicNodeListView = (ListView)view.findViewById(R.id.datatest_public_nodelist_listview); mPublicChatListView = (ListView)view.findViewById(R.id.datatest_public_chat_listview); mInputEditText = (EditText)view.findViewById(R.id.datatest_input_edittext); mInputEditText.setLongClickable(false); mInputEditText.setOnClickListener(this); mInputEditText.setOnTouchListener(new OnTouchListener() { private long lastTouchTime = -1; @Override public boolean onTouch(View arg0, MotionEvent arg1) { if (arg1.getAction() == MotionEvent.ACTION_DOWN) { long thisTime = System.currentTimeMillis(); if (thisTime - lastTouchTime < 250) { // Double tap Log.d(TAG, TAGClass + "onTouch : Double tap!"); mGesture.onTouchEvent(arg1); lastTouchTime = -1; return true; } else { // Too slow lastTouchTime = thisTime; } } return false; } }); mInputEditText.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { boolean handled = false; if (actionId == EditorInfo.IME_ACTION_SEND) { sendMessage(); handled = true; } return handled; } }); mFileSelectButton = (Button)view.findViewById(R.id.datatest_fileselect_button); mFileSelectButton.setOnClickListener(this); mChatListAdapter = new ChatListAdapter(getActivity().getApplicationContext(), this); mChatListView.setAdapter(mChatListAdapter); mChatListView.setOnScrollListener(this); mNodeListAdapter = new NodeListAdapter(getActivity().getApplicationContext(), true); mNodeListView.setAdapter(mNodeListAdapter); mNodeListView.setOnItemClickListener(this); mPublicNodeListAdapter = new NodeListAdapter(getActivity().getApplicationContext(), true); mPublicNodeListView.setAdapter(mPublicNodeListAdapter); mPublicNodeListView.setOnItemClickListener(this); mPublicChatListAdapter = new ChatListAdapter(getActivity().getApplicationContext(), this); mPublicChatListView.setAdapter(mPublicChatListAdapter); mPublicChatListView.setOnScrollListener(this); mAlertDialogMap = new HashMap<String, AlertDialog>(); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { mCallback = (OnChordMessageReceive) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnChordMessageReceive"); } } @Override public void onClick(View v) { ArrayList<String> checkedList = null; Log.d(TAG,"Node List is clicked"); checkedList = getNodeListAdapter(mChannelType).getCheckedNodeList(); if (v.getId() != R.id.datatest_newmessage_textview && v.getId() != R.id.datatest_public_newmessage_textview && v.getId() != R.id.datatest_input_edittext && checkedList.size() == 0) { Toast.makeText(getActivity().getApplicationContext(), getString(R.string.must_select), Toast.LENGTH_SHORT).show(); return; } switch (v.getId()) { case R.id.datatest_newmessage_textview: case R.id.datatest_public_newmessage_textview: getChatListView(mChannelType) .setSelection(getChatListView(mChannelType).getCount()); getNewMessageTextView(mChannelType).setVisibility(View.INVISIBLE); getNewMessageTextView(mChannelType).setText(""); break; case R.id.datatest_fileselect_button: Intent intent = new Intent(); intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); startActivityForResult(intent, GET_CONTENTS); break; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } private boolean isScroll = false; @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (SCROLL_STATE_IDLE == scrollState && view.getLastVisiblePosition() == getChatListAdapter(mChannelType).getCount() - 1) { getNewMessageTextView(mChannelType).setVisibility(View.INVISIBLE); isScroll = false; } else if (SCROLL_STATE_TOUCH_SCROLL == scrollState) { isScroll = true; } } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub if (position != 0) { String ipAddress = mChordService.getNodeIpAddress(mChannelType, getNodeListAdapter(mChannelType).getNodeName(position)); Toast.makeText(getActivity().getApplicationContext(), ipAddress, Toast.LENGTH_SHORT) .show(); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { // TODO Auto-generated method stub if (requestCode == GET_CONTENTS && resultCode == Activity.RESULT_OK) { Log.d(TAG, TAGClass + data.getData()); Uri uri = data.getData(); String scheme = uri.getScheme(); if (null == scheme) { Toast.makeText(getActivity(), R.string.not_support_file, Toast.LENGTH_SHORT).show(); return; } String filePath = null; if (scheme.equals("file")) { filePath = uri.getPath(); } else if (scheme.equals("content")) { String type = getActivity().getContentResolver().getType(uri); Log.d(TAG, TAGClass + type); String[] filePathColumn = { MediaStore.Images.Media.DATA }; Cursor cursor = getActivity().getContentResolver().query(uri, filePathColumn, null, null, null); if ((null == cursor) || (cursor.getCount() < 0)) { Toast.makeText(getActivity(), R.string.not_support_file, Toast.LENGTH_SHORT) .show(); return; } try { cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); filePath = cursor.getString(columnIndex); if (null != filePath) { if (filePath.contains("://")) { int index = filePath.indexOf("://"); filePath = filePath.substring(index + 3); } } } catch (Exception e) { } finally { cursor.close(); } } if (null == filePath) { Toast.makeText(getActivity(), R.string.not_support_file, Toast.LENGTH_SHORT).show(); return; } ArrayList<String> checkedList = getNodeListAdapter(mChannelType).getCheckedNodeList(); for (String nodeName : checkedList) { String exchangeId = mChordService.sendFile(mChannelType, filePath, nodeName); if (null == exchangeId || exchangeId.isEmpty()) { Toast.makeText(getActivity(), getString(R.string.sending_ps_failed, filePath), Toast.LENGTH_SHORT).show(); } else { onFileProgress(true, nodeName, mChannelType, 0, exchangeId); } } } super.onActivityResult(requestCode, resultCode, data); } private void sendMessage() { ArrayList<String> checkedList = getNodeListAdapter(mChannelType).getCheckedNodeList(); if (checkedList.isEmpty()) { Toast.makeText(getActivity().getApplicationContext(), getString(R.string.must_select), Toast.LENGTH_SHORT).show(); return; } String message = mInputEditText.getText().toString(); if (message.equals("") || message == null) { return; } boolean bSent = true; mInputEditText.setText(""); if (getNodeListAdapter(mChannelType).isAllChecked()) { if (!mChordService.sendDataToAll(mChannelType, message.getBytes())) { bSent = false; } } else { for (String nodeName : checkedList) { if (!mChordService.sendData(mChannelType, message.getBytes(), nodeName)) { bSent = false; } } } if (!bSent) { Toast.makeText(getActivity().getApplicationContext(), getString(R.string.sending_failed_message), Toast.LENGTH_SHORT).show(); return; } addMessageToChat(true, mMyNodeName, mChannelType, message); } private void displayFileNotify(final String nodeName, final String channel, final String fileName, final String transactionId) { AlertDialog alertDialog = new AlertDialog.Builder(getActivity()).setTitle(channel) .setMessage(getString(R.string.from_ps_file_ps, nodeName, fileName)) .setPositiveButton(R.string.accept, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { if (mChordService.acceptFile(channel, transactionId)) { addMessageToChat( true, nodeName, channel, getString(R.string.accepted_receiving_ps_from_ps, fileName, mMyNodeName)); onFileProgress(false, nodeName, channel, 0, transactionId); } else { addMessageToChat(true, nodeName, channel, getString(R.string.receiving_ps_failed, fileName, mMyNodeName)); } } }).setNegativeButton(R.string.reject, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub if (!mChordService.rejectFile(channel, transactionId)) Log.e(TAG, TAGClass + "displayFileNotify : fail to rejectFile"); addMessageToChat(true, nodeName, channel, getString(R.string.rejected_receiving_ps, fileName)); } }).create(); alertDialog.show(); alertDialog.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface arg0) { // TODO Auto-generated method stub if (!mChordService.rejectFile(channel, transactionId)) Log.e(TAG, TAGClass + "displayFileNotify : fail to rejectFile"); addMessageToChat(true, nodeName, channel, getString(R.string.rejected_receiving_ps, fileName)); } }); mAlertDialogMap.put(transactionId, alertDialog); } private void addMessageToChat(boolean bMine, String nodeName, String channel, String message) { getChatListAdapter(channel).addChat(bMine, nodeName, message); moveChatScrollToBottom(bMine, nodeName, channel, message); } private void moveChatScrollToBottom(boolean bMine, String nodeName, String channel, String message) { if (!channel.equals(mChannelType)) { return; } if (bMine || getChatListView(channel).getLastVisiblePosition() >= getChatListAdapter(channel) .getCount() - 2) { if (isScroll) { return; } getChatListView(channel).setSelection(getChatListView(channel).getCount()); getNewMessageTextView(mChannelType).setVisibility(View.INVISIBLE); } else { getNewMessageTextView(mChannelType).setVisibility(View.VISIBLE); getNewMessageTextView(mChannelType).setText( getString(R.string.new_message, nodeName, message)); } } // ********************************************************************** // For the Activity // ********************************************************************** public void setMyNodeInfo(String nodeName, String ipAddress) { mMyNodeName = nodeName; mMyNodeNameTextView.setText(nodeName); mMyIpAddressTextView.setText(ipAddress); } public void setChannelName(String channelName) { mChannelType = channelName; if (isPublicChannel(mChannelType)) { mPublicNodeListView.setVisibility(View.VISIBLE); mPublicChatListView.setVisibility(View.VISIBLE); mNodeListView.setVisibility(View.GONE); mChatListView.setVisibility(View.GONE); mNewMessageTextView.setVisibility(View.INVISIBLE); if (!mPublicNewMessageTextView.getText().equals("")) { mPublicNewMessageTextView.setVisibility(View.VISIBLE); } else { mPublicNewMessageTextView.setVisibility(View.INVISIBLE); } } else { mNodeListView.setVisibility(View.VISIBLE); mChatListView.setVisibility(View.VISIBLE); mPublicNodeListView.setVisibility(View.GONE); mPublicChatListView.setVisibility(View.GONE); mPublicNewMessageTextView.setVisibility(View.INVISIBLE); if (!mNewMessageTextView.getText().equals("")) { mNewMessageTextView.setVisibility(View.VISIBLE); } else { mNewMessageTextView.setVisibility(View.INVISIBLE); } } mChannelNameTextView.setText(channelName); } public void setService(ChordApiDemoService chordService) { mChordService = chordService; } public void clearAllData() { Log.d(TAG, TAGClass + "leaveChannel : cleatAllData()"); mNodeListAdapter.clearAll(); mChatListAdapter.clearAll(); mPublicNodeListAdapter.clearAll(); mPublicChatListAdapter.clearAll(); mPublicNewMessageTextView.setVisibility(View.INVISIBLE); mPublicNewMessageTextView.setText(""); mNewMessageTextView.setVisibility(View.INVISIBLE); mNewMessageTextView.setText(""); mAlertDialogMap.clear(); } public void clearJoinedChannelData() { mNodeListAdapter.clearAll(); mChatListAdapter.clearAll(); mNewMessageTextView.setVisibility(View.INVISIBLE); mNewMessageTextView.setText(""); } public void onMessageReceived(String nodeName, String channel, String message) { // Show notification to the user for new message mCallback.onChordMessageReceive(message); addMessageToChat(false, nodeName, channel, message); } public void onFileNotify(String nodeName, String channel, String fileName, String transactionId) { displayFileNotify(nodeName, channel, fileName, transactionId); } public void onFileProgress(boolean bSend, String nodeName, String channel, int progress, String exchangeId) { Log.d(TAG, TAGClass + "onFileProgress : " + exchangeId); String message = bSend ? getString(R.string.sending_to_ps, nodeName) : getString( R.string.receiving_from_ps, nodeName); getChatListAdapter(channel).addFileLog(bSend, bSend ? mMyNodeName : nodeName, progress, exchangeId, message); if (progress == 0 && getChatListView(channel).getLastVisiblePosition() >= getChatListView(channel) .getCount() - 3) { getChatListView(channel).setSelection(getChatListView(channel).getCount()); } } public void onFileCompleted(int reason, String nodeName, String channel, String fileName, String exchangeId) { Log.d(TAG, TAGClass + "onFileCompleted : " + exchangeId); String msg = null; boolean bMine = true; if (IChordServiceListener.SENT == reason) { bMine = true; msg = getString(R.string.ps_sent_to_ps, fileName, nodeName); getChatListAdapter(channel).addFileCompleteLog(bMine, mMyNodeName, msg, exchangeId); } else if (IChordServiceListener.RECEIVED == reason) { bMine = false; msg = getString(R.string.ps_receive_from_ps, fileName, mMyNodeName); getChatListAdapter(channel).addFileCompleteLog(bMine, nodeName, msg, exchangeId); } else if (IChordServiceListener.REJECTED == reason) { bMine = false; msg = getString(R.string.sending_ps_rejected_by_ps, fileName, nodeName); getChatListAdapter(channel).addFileCompleteLog(bMine, nodeName, msg, exchangeId); } else if (IChordServiceListener.CANCELLED == reason) { bMine = nodeName.equals(mMyNodeName) ? true : false; if (!bMine) { AlertDialog alertDialog = mAlertDialogMap.get(exchangeId); if (alertDialog != null) { alertDialog.dismiss(); mAlertDialogMap.remove(exchangeId); } } msg = getString(R.string.ps_transfer_cancelled_by_ps, fileName, nodeName); getChatListAdapter(channel).addFileCompleteLog(bMine, nodeName, msg, exchangeId); } else if (IChordServiceListener.FAILED == reason) { if (nodeName.equals(mMyNodeName)) { bMine = true; msg = getString(R.string.sending_ps_failed, fileName); } else { bMine = false; AlertDialog alertDialog = mAlertDialogMap.get(exchangeId); if (alertDialog != null) { alertDialog.dismiss(); mAlertDialogMap.remove(exchangeId); } msg = getString(R.string.receiving_ps_failed, fileName); } getChatListAdapter(channel).addFileCompleteLog(bMine, nodeName, msg, exchangeId); } moveChatScrollToBottom(bMine, nodeName, channel, msg); } public void onNodeJoined(String nodeName, String channel) { Log.d(TAG, TAGClass + "Node join : " + nodeName); getNodeListAdapter(channel).addNode(nodeName); } public void onNodeLeaved(String nodeName, String channel) { Log.d(TAG, TAGClass + "Node leave : " + nodeName); getNodeListAdapter(channel).removeNode(nodeName); } public void onNetworkDisconnected() { Log.d(TAG, TAGClass + "Network disconnected : clear node list"); mNodeListAdapter.clearAll(); mPublicNodeListAdapter.clearAll(); mMyIpAddressTextView.setText("Disconnected"); } private boolean isPublicChannel(String channel) { if (channel.equals(mChordService.getPublicChannel())) { return true; } return false; } private NodeListAdapter getNodeListAdapter(String channel) { if (isPublicChannel(channel)) { return mPublicNodeListAdapter; } return mNodeListAdapter; } private ChatListAdapter getChatListAdapter(String channel) { if (isPublicChannel(channel)) { return mPublicChatListAdapter; } return mChatListAdapter; } private ListView getChatListView(String channel) { if (isPublicChannel(channel)) { return mPublicChatListView; } return mChatListView; } private TextView getNewMessageTextView(String channel) { if (isPublicChannel(channel)) { return mPublicNewMessageTextView; } return mNewMessageTextView; } // ********************************************************************** // From adapter // ********************************************************************** @Override public void onCancelFileButtonClick(String exchangeId) { if (!mChordService.cancelFile(mChannelType, exchangeId)) { Log.e(TAG, TAGClass + "onCancelFileButtonClick : fail to cancel!"); } } }