org.restcomm.android.olympus.MessageFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.restcomm.android.olympus.MessageFragment.java

Source

/*
 * TeleStax, Open Source Cloud Communications
 * Copyright 2011-2015, Telestax Inc and individual contributors
 * by the @authors tag.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 * For questions related to commercial use licensing, please contact sales@telestax.com.
 *
 */

package org.restcomm.android.olympus;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

import org.restcomm.android.sdk.RCClient;
import org.restcomm.android.sdk.RCDevice;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class MessageFragment extends ListFragment {
    private SimpleCursorAdapter listViewAdapter;
    private ArrayList<Map<String, String>> messageList;
    public static final String MESSAGE_CONTACT_KEY = "username";
    public static final String MESSAGE_TEXT_KEY = "message-text";
    /**
     * The serialization (saved instance state) Bundle key representing the
     * activated item position. Only used on tablets.
     */
    private static final String STATE_ACTIVATED_POSITION = "activated_position";

    /**
     * The fragment's current callback object, which is notified of list item
     * clicks.
     */
    private Callbacks mCallbacks = null;

    /**
     * The current activated item position. Only used on tablets.
     */
    private int mActivatedPosition = ListView.INVALID_POSITION;

    /**
     * A callback interface that all activities containing this fragment must
     * implement. This mechanism allows activities to be notified of item
     * selections.
     */
    public interface Callbacks {
        /**
         * Callback for when an item has been selected.
         */
        //public void onItemSelected(HashMap<String, String> contact, ContactSelectionType type);
        //public void onContactUpdate(HashMap<String, String> contact, int type);
    }

    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public MessageFragment() {
    }

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

        // Use MessageActivity intent to retrieve the contact name
        final Intent intent = getActivity().getIntent();
        String contactName = intent.getStringExtra(RCDevice.EXTRA_DID).replaceAll("^sip:", "").replaceAll("@.*$",
                "");
        //listFragment = (MessageFragment) getSupportFragmentManager().findFragmentById(R.id.message_list);
        //Bundle args = new Bundle();
        //args.putString("contact-name", shortname);
        //listFragment.setArguments(args);

        /*
        Bundle args = getArguments();
        String contactName = args.getString("contact-name");
        */
        DatabaseManager.getInstance().open(getActivity().getApplicationContext());

        // TODO: this must be done in the background
        Cursor cursor = DatabaseManager.getInstance().retrieveMessages(contactName);

        String[] fromColumns = { DatabaseContract.ContactEntry.COLUMN_NAME_NAME,
                DatabaseContract.MessageEntry.COLUMN_NAME_TEXT,
                DatabaseContract.MessageEntry.COLUMN_NAME_DELIVERY_STATUS };
        int[] toViews = { R.id.message_username, R.id.message_text, R.id.message_status };

        listViewAdapter = new SimpleCursorAdapter(getActivity().getApplicationContext(),
                R.layout.message_row_layout, cursor, fromColumns, toViews, 0);

        // Use a binder for the delivery status column which doesn't map 1-on-1 with the view: status in the db is an integer, while in the view it's a string
        listViewAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
            @Override
            public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
                if (cursor.getColumnName(columnIndex)
                        .equals(DatabaseContract.MessageEntry.COLUMN_NAME_DELIVERY_STATUS)) {
                    TextView deliveryStatusView = (TextView) view;
                    if (cursor.getString(cursor.getColumnIndex(DatabaseContract.MessageEntry.COLUMN_NAME_TYPE))
                            .equals("local")) {
                        int deliveryStatus = cursor.getInt(columnIndex);
                        if (deliveryStatus == DatabaseContract.MessageDeliveryStatus.TEXT_MESSAGE_PENDING
                                .ordinal()) {
                            deliveryStatusView.setText("...");
                            deliveryStatusView.setTextColor(
                                    ContextCompat.getColor(getActivity(), R.color.colorTextSecondary));
                        } else if (deliveryStatus == DatabaseContract.MessageDeliveryStatus.TEXT_MESSAGE_FAILED
                                .ordinal()) {
                            deliveryStatusView.setText("Failed");
                            deliveryStatusView
                                    .setTextColor(ContextCompat.getColor(getActivity(), R.color.colorError));
                        } else {
                            deliveryStatusView.setText("Success");
                            deliveryStatusView.setTextColor(
                                    ContextCompat.getColor(getActivity(), R.color.colorTextSecondary));
                        }
                    } else {
                        // remote message
                        deliveryStatusView.setText("");
                    }
                    return true;
                }

                if (cursor.getColumnName(columnIndex).equals(DatabaseContract.ContactEntry.COLUMN_NAME_NAME)) {
                    TextView usernameView = (TextView) view;
                    if (cursor.getString(cursor.getColumnIndex(DatabaseContract.MessageEntry.COLUMN_NAME_TYPE))
                            .equals("local")) {
                        usernameView.setText("Me");
                        return true;
                    }
                }

                return false;
            }
        });

        setListAdapter(listViewAdapter);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        getListView().setDivider(null);
        getListView().setDividerHeight(0);

        // Restore the previously serialized activated item position.
        if (savedInstanceState != null && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
            setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
        }

        registerForContextMenu(getListView());
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // Activities containing this fragment must implement its callbacks.
        if (!(activity instanceof Callbacks)) {
            throw new IllegalStateException("Activity must implement fragment's callbacks.");
        }

        mCallbacks = (Callbacks) activity;
    }

    @Override
    public void onDetach() {
        super.onDetach();

        // Reset the active callbacks interface to the dummy implementation.
        mCallbacks = null;
    }

    @Override
    public void onListItemClick(ListView listView, View view, int position, long id) {
        super.onListItemClick(listView, view, position, id);

        // no actions for now when tapping on an item
        /*
        HashMap item = (HashMap)getListView().getItemAtPosition(position);
        // Notify the active callbacks interface (the activity, if the
        // fragment is attached to one) that an item has been selected.
        mCallbacks.onItemSelected(item, ContactSelectionType.VIDEO_CALL);
        */
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mActivatedPosition != ListView.INVALID_POSITION) {
            // Serialize and persist the activated item position.
            outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
        }
    }

    /**
     * Turns on activate-on-click mode. When this mode is on, list items will be
     * given the 'activated' state when touched.
     */
    public void setActivateOnItemClick(boolean activateOnItemClick) {
        // When setting CHOICE_MODE_SINGLE, ListView will automatically
        // give items the 'activated' state when touched.
        getListView().setChoiceMode(activateOnItemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE);
    }

    private void setActivatedPosition(int position) {
        if (position == ListView.INVALID_POSITION) {
            getListView().setItemChecked(mActivatedPosition, false);
        } else {
            getListView().setItemChecked(position, true);
        }

        mActivatedPosition = position;
    }

    // Called by Activity when when new message is sent
    public int addLocalMessage(String message, String username, String jobId) {
        int countBeforeAddition = listViewAdapter.getCount();
        DatabaseManager.getInstance().addMessage(username, message, true, jobId,
                DatabaseContract.MessageDeliveryStatus.TEXT_MESSAGE_PENDING);

        // TODO: this must be done in the background
        Cursor cursor = DatabaseManager.getInstance().retrieveMessages(username);
        // update adapter cursor to use the new one with updated rows
        this.listViewAdapter.changeCursor(cursor);
        this.listViewAdapter.notifyDataSetChanged();
        getListView().setSelection(listViewAdapter.getCount() - 1);
        return countBeforeAddition;
    }

    // Called by Activity when when new message is sent
    public void addRemoteMessage(String message, String username) {
        DatabaseManager.getInstance().addMessage(username, message, false, null,
                DatabaseContract.MessageDeliveryStatus.TEXT_MESSAGE_DELIVERED);

        // TODO: this must be done in the background
        Cursor cursor = DatabaseManager.getInstance().retrieveMessages(username);
        // update adapter cursor to use the new one with updated rows
        this.listViewAdapter.changeCursor(cursor);
        this.listViewAdapter.notifyDataSetChanged();
        getListView().setSelection(listViewAdapter.getCount() - 1);
    }

    public void updateMessageDeliveryStatus(String jobId, int statusCode, String username) {
        DatabaseContract.MessageDeliveryStatus deliveryStatus = DatabaseContract.MessageDeliveryStatus.TEXT_MESSAGE_DELIVERED;
        if (statusCode != RCClient.ErrorCodes.SUCCESS.ordinal()) {
            deliveryStatus = DatabaseContract.MessageDeliveryStatus.TEXT_MESSAGE_FAILED;
        }

        DatabaseManager.getInstance().updateMessageStatus(jobId, deliveryStatus);
        // TODO: this must be done in the background
        Cursor cursor = DatabaseManager.getInstance().retrieveMessages(username);
        // update adapter cursor to use the new one with updated rows
        this.listViewAdapter.changeCursor(cursor);
        this.listViewAdapter.notifyDataSetChanged();
    }

    /*
    public ListView getFragmentListView()
    {
       return getListView();
    }
    */

    // Helper methods
    private void showOkAlert(final String title, final String detail) {
        AlertDialog alertDialog = new AlertDialog.Builder(getActivity()).create();
        alertDialog.setTitle(title);
        alertDialog.setMessage(detail);
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        alertDialog.show();
    }

}