/* * Created by Itzik Braun on 12/3/2015. * Copyright (c) 2015 deluge. All rights reserved. * * Last Modification at: 3/12/15 4:27 PM */ package com.braunster.chatsdk.fragments.abstracted; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.TimingLogger; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.ProgressBar; import com.braunster.chatsdk.R; import com.braunster.chatsdk.Utils.Debug; import com.braunster.chatsdk.activities.abstracted.ChatSDKAbstractChatActivity; import com.braunster.chatsdk.adapter.ChatSDKThreadsListAdapter; import com.braunster.chatsdk.adapter.abstracted.ChatSDKAbstractThreadsListAdapter; import com.braunster.chatsdk.dao.BThread; import com.braunster.chatsdk.dao.entities.Entity; import com.braunster.chatsdk.fragments.ChatSDKBaseFragment; import com.braunster.chatsdk.network.BNetworkManager; import com.braunster.chatsdk.network.events.BatchedEvent; import com.braunster.chatsdk.network.events.Event; import com.braunster.chatsdk.object.Batcher; import com.braunster.chatsdk.object.UIUpdater; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * Created by itzik on 6/17/2014. */ public class ChatSDKAbstractConversationsFragment extends ChatSDKBaseFragment { private static final String TAG = ChatSDKAbstractConversationsFragment.class.getSimpleName(); private static boolean DEBUG = Debug.ConversationsFragment; public static final String APP_EVENT_TAG= "ConverstaionFragment"; protected ListView listThreads; protected ChatSDKAbstractThreadsListAdapter adapter; protected ProgressBar progressBar; protected TimingLogger timings; protected UIUpdater uiUpdater; protected boolean inflateMenuItems = true; protected AdapterView.OnItemLongClickListener onItemLongClickListener; protected AdapterView.OnItemClickListener onItemClickListener; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActivity().registerReceiver(receiver, new IntentFilter(ChatSDKAbstractChatActivity.ACTION_CHAT_CLOSED)); } @Override public void initViews() { listThreads = (ListView) mainView.findViewById(R.id.list_threads); progressBar = (ProgressBar) mainView.findViewById(R.id.chat_sdk_progress_bar); initList(); } private void initList(){ // Create the adpater only if null, This is here so we wont override the adapter given from the extended class with setAdapter. if (adapter == null) adapter = new ChatSDKThreadsListAdapter(getActivity()); listThreads.setAdapter(adapter); if (onItemClickListener==null) { onItemClickListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { startChatActivityForID(adapter.getItem(position).getId()); } }; } listThreads.setOnItemClickListener(onItemClickListener); if (onItemLongClickListener== null) { onItemLongClickListener = new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { showAlertDialog("", getResources().getString(R.string.alert_delete_thread), getResources().getString(R.string.delete), getResources().getString(R.string.cancel), null, new DeleteThread(adapter.getItem(position).getEntityId())); return true; } }; } listThreads.setOnItemLongClickListener(onItemLongClickListener); } @Override public void loadData() { super.loadData(); if (mainView == null) return; adapter.setThreadItems(BNetworkManager.sharedManager().getNetworkAdapter().threadItemsWithType(BThread.Type.Private, adapter.getItemMaker())); } @Override public void loadDataOnBackground() { super.loadDataOnBackground(); if (DEBUG) timings = new TimingLogger(TAG.substring(0, 21), "loadDataOnBackground"); if (mainView == null) { return; } final boolean isFirst; if (uiUpdater != null) { isFirst = false; uiUpdater.setKilled(true); ChatSDKAbstractConversationsFragmentChatSDKThreadPool.getInstance().removeSchedule(uiUpdater); } else { isFirst = true; } final boolean hasItems = adapter != null && adapter.getThreadItems().size() > 0; if (isFirst && !hasItems) { loadData(); } uiUpdater = new UIUpdater() { @Override public void run() { if (isKilled() && !isFirst && hasItems) { return; } if (DEBUG) { timings.addSplit("Loading threads"); } List list = BNetworkManager.sharedManager().getNetworkAdapter().threadItemsWithType(BThread.Type.Private, adapter.getItemMaker()); if (DEBUG) { timings.addSplit("Loading threads"); } uiUpdater = null; Message message = new Message(); message.obj = list; message.what = 1; handler.sendMessageAtFrontOfQueue(message); if (DEBUG) timings.addSplit("Sending message to handler."); } }; ChatSDKAbstractConversationsFragmentChatSDKThreadPool.getInstance().scheduleExecute(uiUpdater,isFirst ? 1 : 0); } @Override public void refreshForEntity(Entity entity) { super.refreshForEntity(entity); if (adapter.getCount() == 0) return;; adapter.replaceOrAddItem((BThread) entity); if (progressBar.getVisibility() == View.VISIBLE) { progressBar.setVisibility(View.GONE); listThreads.setVisibility(View.VISIBLE); } } @Override public void clearData() { if (adapter != null) { if (uiUpdater != null) uiUpdater.setKilled(true); adapter.getThreadItems().clear(); adapter.notifyDataSetChanged(); } } private class UpdateHandler extends Handler{ public UpdateHandler(Looper mainLooper) { super(mainLooper); } @SuppressWarnings("unchecked") @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: adapter.setThreadItems((List<ChatSDKThreadsListAdapter.ThreadListItem>) msg.obj); if (progressBar.getVisibility() == View.VISIBLE) { progressBar.setVisibility(View.INVISIBLE); listThreads.setVisibility(View.VISIBLE); } if (DEBUG) { timings.addSplit("Updating UI"); timings.dumpToLog(); timings.reset(TAG.substring(0, 21), "loadDataOnBackground"); } break; } } } private UpdateHandler handler = new UpdateHandler(Looper.getMainLooper()); @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { if (!inflateMenuItems) return; super.onCreateOptionsMenu(menu, inflater); MenuItem item = menu.add(Menu.NONE, R.id.action_chat_sdk_add, 10, "Add Conversation"); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); item.setIcon(R.drawable.ic_plus); } @Override public boolean onOptionsItemSelected(MenuItem item){ if (!inflateMenuItems) return super.onOptionsItemSelected(item); /* Cant use switch in the library*/ int id = item.getItemId(); if (id == R.id.action_chat_sdk_add) { startPickFriendsActivity(); return true; } return super.onOptionsItemSelected(item); } @Override public void onResume() { super.onResume(); // loadDataOnBackground(); BatchedEvent batchedEvents = new BatchedEvent(APP_EVENT_TAG, "", Event.Type.AppEvent, handler); batchedEvents.setBatchedAction(Event.Type.AppEvent, 3000, new Batcher.BatchedAction<String>() { @Override public void triggered(List<String> list) { loadDataOnBackground(); } }); getNetworkAdapter().getEventManager().removeEventByTag(APP_EVENT_TAG); getNetworkAdapter().getEventManager().addEvent(batchedEvents); } @Override public void onDestroy() { super.onDestroy(); try { getActivity().unregisterReceiver(receiver); } catch (Exception e) { } } public void setAdapter(ChatSDKAbstractThreadsListAdapter adapter) { this.adapter = adapter; } public void setInflateMenuItems(boolean inflateMenuItems) { this.inflateMenuItems = inflateMenuItems; } public void filterThreads(String text){ adapter.filterItems(text); } private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(ChatSDKAbstractChatActivity.ACTION_CHAT_CLOSED)) { loadDataOnBackground(); } } }; public ChatSDKAbstractThreadsListAdapter getAdapter() { return adapter; } /** FIXME not sure if needed. * Created by braunster on 18/08/14. */ private static class ChatSDKAbstractConversationsFragmentChatSDKThreadPool { // Sets the amount of time an idle thread waits before terminating private static final int KEEP_ALIVE_TIME = 3; // Sets the Time Unit to seconds private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS; private LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(); /* * Gets the number of available cores * (not always the same as the maximum number of cores) */ private static int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); private ThreadPoolExecutor threadPool; private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; private static ChatSDKAbstractConversationsFragmentChatSDKThreadPool instance; public static ChatSDKAbstractConversationsFragmentChatSDKThreadPool getInstance() { if (instance == null) instance = new ChatSDKAbstractConversationsFragmentChatSDKThreadPool(); return instance; } private ChatSDKAbstractConversationsFragmentChatSDKThreadPool(){ if (NUMBER_OF_CORES <= 0) NUMBER_OF_CORES = 2; // Creates a thread pool manager threadPool = new ThreadPoolExecutor( NUMBER_OF_CORES, // Initial pool size NUMBER_OF_CORES, // Max pool size KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, workQueue); scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(NUMBER_OF_CORES); } public void execute(Runnable runnable){ threadPool.execute(runnable); } public void scheduleExecute(Runnable runnable, long delay){ scheduledThreadPoolExecutor.schedule(runnable, delay, TimeUnit.SECONDS); } public boolean removeSchedule(Runnable runnable){ return scheduledThreadPoolExecutor.remove(runnable); } } }