im.vector.activity.VectorUnifiedSearchActivity.java Source code

Java tutorial

Introduction

Here is the source code for im.vector.activity.VectorUnifiedSearchActivity.java

Source

/*
 * Copyright 2016 OpenMarket Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package im.vector.activity;

import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.support.v7.app.ActionBar.TabListener;
import android.widget.Toast;

import org.matrix.androidsdk.MXSession;
import org.matrix.androidsdk.fragments.MatrixMessageListFragment;

import im.vector.Matrix;
import im.vector.PublicRoomsManager;
import im.vector.R;
import im.vector.contacts.ContactsManager;
import im.vector.fragments.VectorSearchPeopleListFragment;
import im.vector.fragments.VectorSearchRoomsFilesListFragment;
import im.vector.fragments.VectorSearchRoomsListFragment;
import im.vector.fragments.VectorSearchMessagesListFragment;

/**
 * Displays a generic activity search method
 */
public class VectorUnifiedSearchActivity extends VectorBaseSearchActivity
        implements TabListener, VectorBaseSearchActivity.IVectorSearchActivity {
    private static final String LOG_TAG = "VectorUniSrchActivity";
    private static final CharSequence NOT_IMPLEMENTED = "Not yet implemented";

    // tab related items
    private static final String TAG_FRAGMENT_SEARCH_IN_MESSAGE = "im.vector.activity.TAG_FRAGMENT_SEARCH_IN_MESSAGE";
    private static final String TAG_FRAGMENT_SEARCH_IN_ROOM_NAMES = "im.vector.activity.TAG_FRAGMENT_SEARCH_IN_ROOM_NAMES";
    private static final String TAG_FRAGMENT_SEARCH_PEOPLE = "im.vector.activity.TAG_FRAGMENT_SEARCH_PEOPLE";
    private static final String TAG_FRAGMENT_SEARCH_IN_FILES = "im.vector.activity.TAG_FRAGMENT_SEARCH_IN_FILES";
    private int mSearchInRoomNamesTabIndex = -1;
    private int mSearchInMessagesTabIndex = -1;
    private int mSearchInPeopleTabIndex = -1;
    private int mSearchInFilesTabIndex = -1;
    private int mCurrentTabIndex = -1;

    // activity life cycle management:
    // - Bundle keys
    private static final String KEY_STATE_CURRENT_TAB_INDEX = "CURRENT_SELECTED_TAB";
    private static final String KEY_STATE_SEARCH_PATTERN = "SEARCH_PATTERN";
    private static final String KEY_STATE_IS_PERMISSIONS_GRANTED = "PERMISSIONS_STATUS";

    // search fragments
    private VectorSearchMessagesListFragment mSearchInMessagesFragment;
    private VectorSearchRoomsListFragment mSearchInRoomNamesFragment;
    private VectorSearchRoomsFilesListFragment mSearchInFilesFragment;
    private VectorSearchPeopleListFragment mSearchInPeopleFragment;
    private MXSession mSession;

    // UI items
    private ImageView mBackgroundImageView;
    private TextView mNoResultsTxtView;
    private View mLoadOldestContentView;
    private View mWaitWhileSearchInProgressView;

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

        if (CommonActivityUtils.shouldRestartApp(this)) {
            Log.e(LOG_TAG, "Restart the application.");
            CommonActivityUtils.restartApp(this);
            return;
        }

        if (CommonActivityUtils.isGoingToSplash(this)) {
            Log.d(LOG_TAG, "onCreate : Going to splash screen");
            return;
        }

        // the session should be passed in parameter
        // but the current design does not describe how the multi accounts will be managed.
        mSession = Matrix.getInstance(this).getDefaultSession();
        if (mSession == null) {
            Log.e(LOG_TAG, "No MXSession.");
            finish();
            return;
        }

        // UI widgets binding & init fields
        mBackgroundImageView = (ImageView) findViewById(R.id.search_background_imageview);
        mNoResultsTxtView = (TextView) findViewById(R.id.search_no_result_textview);
        mWaitWhileSearchInProgressView = findViewById(R.id.search_in_progress_view);
        mLoadOldestContentView = findViewById(R.id.search_load_oldest_progress);

        // tab creation and restore tabs UI context
        createNavigationTabs(savedInstanceState);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onPatternUpdate(boolean isTypingUpdate) {
        // the messages searches are not done locally.
        // so, such searches can only be done if the user taps on the search button.
        if (isTypingUpdate && ((mCurrentTabIndex == mSearchInMessagesTabIndex)
                || (mCurrentTabIndex == mSearchInFilesTabIndex))) {
            return;
        }

        searchAccordingToTabHandler();
    }

    /**
     * Reset the UI to its init state:
     * - "waiting while searching" screen disabled
     * - background image visible
     * - no results message disabled
     * @param showBackgroundImage true to display it
     */
    private void resetUi(boolean showBackgroundImage) {
        // stop "wait while searching" screen
        if (null != mWaitWhileSearchInProgressView) {
            mWaitWhileSearchInProgressView.setVisibility(View.GONE);
        }

        // display the background
        if (null != mBackgroundImageView) {
            mBackgroundImageView.setVisibility(showBackgroundImage ? View.VISIBLE : View.GONE);
        }

        if (null != mNoResultsTxtView) {
            mNoResultsTxtView.setVisibility(View.GONE);
        }

        if (null != mLoadOldestContentView) {
            mLoadOldestContentView.setVisibility(View.GONE);
        }
    }

    /**
     * The search is done.
     * @param tabIndex the tab index
     * @param nbrMessages the number of found messages.
     */
    private void onSearchEnd(int tabIndex, int nbrMessages) {
        if (mCurrentTabIndex == tabIndex) {
            Log.d(LOG_TAG, "## onSearchEnd() nbrMsg=" + nbrMessages);
            // stop "wait while searching" screen
            mWaitWhileSearchInProgressView.setVisibility(View.GONE);

            // display the background view if there is no pending such
            mBackgroundImageView.setVisibility(
                    (0 == nbrMessages) && TextUtils.isEmpty(mPatternToSearchEditText.getText().toString())
                            ? View.VISIBLE
                            : View.GONE);

            // display the "no result" text only if the researched text is not empty
            mNoResultsTxtView.setVisibility(
                    ((0 == nbrMessages) && !TextUtils.isEmpty(mPatternToSearchEditText.getText().toString()))
                            ? View.VISIBLE
                            : View.GONE);
        }
    }

    /**
     * Trigger a search into the selected tab.
     */
    private void searchAccordingToTabHandler() {
        int currentIndex = mActionBar.getSelectedNavigationIndex();

        String pattern = mPatternToSearchEditText.getText().toString();

        // the background image view should only be displayed when there is no patter,
        // the rooms searches has a result : the public rooms list.
        resetUi(TextUtils.isEmpty(pattern) && (currentIndex != mSearchInRoomNamesTabIndex));

        if ((currentIndex == mSearchInRoomNamesTabIndex) && (null != mSearchInRoomNamesFragment)) {
            // display a spinner if the public rooms list are not yet initialized
            // else the search should be quite fast because it is only performed on the known rooms list/
            if (null == PublicRoomsManager.getPublicRooms()) {
                mWaitWhileSearchInProgressView.setVisibility(View.VISIBLE);
            }

            mSearchInRoomNamesFragment.searchPattern(pattern,
                    new MatrixMessageListFragment.OnSearchResultListener() {
                        @Override
                        public void onSearchSucceed(int nbrMessages) {
                            onSearchEnd(mSearchInRoomNamesTabIndex, nbrMessages);
                        }

                        @Override
                        public void onSearchFailed() {
                            onSearchEnd(mSearchInRoomNamesTabIndex, 0);
                        }
                    });
        } else if ((currentIndex == mSearchInMessagesTabIndex) && (null != mSearchInMessagesFragment)) {
            // display the "wait while searching" screen (progress bar)
            mWaitWhileSearchInProgressView.setVisibility(View.VISIBLE);

            mSearchInMessagesFragment.searchPattern(pattern,
                    new MatrixMessageListFragment.OnSearchResultListener() {
                        @Override
                        public void onSearchSucceed(int nbrMessages) {
                            onSearchEnd(mSearchInMessagesTabIndex, nbrMessages);
                        }

                        @Override
                        public void onSearchFailed() {
                            onSearchEnd(mSearchInMessagesTabIndex, 0);
                        }
                    });
        } else if ((currentIndex == mSearchInFilesTabIndex) && (null != mSearchInFilesFragment)) {
            // display the "wait while searching" screen (progress bar)
            mWaitWhileSearchInProgressView.setVisibility(View.VISIBLE);

            mSearchInFilesFragment.searchPattern(pattern, new MatrixMessageListFragment.OnSearchResultListener() {
                @Override
                public void onSearchSucceed(int nbrMessages) {
                    onSearchEnd(mSearchInFilesTabIndex, nbrMessages);
                }

                @Override
                public void onSearchFailed() {
                    onSearchEnd(mSearchInFilesTabIndex, 0);
                }
            });
        } else if ((currentIndex == mSearchInPeopleTabIndex) && (null != mSearchInPeopleFragment)) {

            if (!mSearchInPeopleFragment.isReady()) {
                mWaitWhileSearchInProgressView.setVisibility(View.VISIBLE);
            }

            mSearchInPeopleFragment.searchPattern(pattern, new MatrixMessageListFragment.OnSearchResultListener() {
                @Override
                public void onSearchSucceed(int nbrMessages) {
                    onSearchEnd(mSearchInPeopleTabIndex, nbrMessages);
                }

                @Override
                public void onSearchFailed() {
                    onSearchEnd(mSearchInPeopleTabIndex, 0);
                }
            });
        } else {
            onSearchEnd(currentIndex, 0);
            Toast.makeText(VectorUnifiedSearchActivity.this, NOT_IMPLEMENTED, Toast.LENGTH_SHORT).show();
        }
    }

    //==============================================================================================================
    // Tabs logic implementation
    //==============================================================================================================

    /**
     * Create the search fragment instances from the saved instance;
     * @param aSavedInstanceState the saved instance.
     */
    private void createNavigationTabs(Bundle aSavedInstanceState) {
        int tabIndex = 0;
        int tabIndexToRestore;

        // Set the tabs navigation mode
        mActionBar.setNavigationMode(android.support.v7.app.ActionBar.NAVIGATION_MODE_TABS);

        // ROOMS names search tab creation
        android.support.v7.app.ActionBar.Tab tabToBeAdded = mActionBar.newTab();
        String tabTitle = getResources().getString(R.string.tab_title_search_rooms);
        tabToBeAdded.setText(tabTitle);
        tabToBeAdded.setTabListener(this);
        tabToBeAdded.setTag(TAG_FRAGMENT_SEARCH_IN_ROOM_NAMES);
        mActionBar.addTab(tabToBeAdded);
        mSearchInRoomNamesTabIndex = tabIndex++;

        // MESSAGES search tab creation
        tabToBeAdded = mActionBar.newTab();
        tabTitle = getResources().getString(R.string.tab_title_search_messages);
        tabToBeAdded.setText(tabTitle);
        tabToBeAdded.setTabListener(this);
        tabToBeAdded.setTag(TAG_FRAGMENT_SEARCH_IN_MESSAGE);
        mActionBar.addTab(tabToBeAdded);
        mSearchInMessagesTabIndex = tabIndex++;

        // PEOPLE search tab creation
        tabToBeAdded = mActionBar.newTab();
        tabTitle = getResources().getString(R.string.tab_title_search_people);
        tabToBeAdded.setText(tabTitle);
        tabToBeAdded.setTabListener(this);
        tabToBeAdded.setTag(TAG_FRAGMENT_SEARCH_PEOPLE);
        mActionBar.addTab(tabToBeAdded);
        mSearchInPeopleTabIndex = tabIndex++;

        // FILES search tab creation
        tabToBeAdded = mActionBar.newTab();
        tabTitle = getResources().getString(R.string.tab_title_search_files);
        tabToBeAdded.setText(tabTitle);
        tabToBeAdded.setTabListener(this);
        tabToBeAdded.setTag(TAG_FRAGMENT_SEARCH_IN_FILES);
        mActionBar.addTab(tabToBeAdded);
        mSearchInFilesTabIndex = tabIndex++;

        // set the default tab to be displayed
        tabIndexToRestore = (null != aSavedInstanceState)
                ? aSavedInstanceState.getInt(KEY_STATE_CURRENT_TAB_INDEX, 0)
                : 0;
        if (-1 == tabIndexToRestore) {
            // default value: display the search in rooms tab
            tabIndexToRestore = mSearchInRoomNamesTabIndex;
        }
        mCurrentTabIndex = tabIndexToRestore;
        // set the tab to display
        mActionBar.setSelectedNavigationItem(tabIndexToRestore);

        // restore the searched pattern
        mPatternToSearchEditText.setText(
                (null != aSavedInstanceState) ? aSavedInstanceState.getString(KEY_STATE_SEARCH_PATTERN, null)
                        : null);
    }

    @Override
    public void onTabSelected(android.support.v7.app.ActionBar.Tab tab,
            android.support.v4.app.FragmentTransaction ft) {
        Log.d(LOG_TAG, "## onTabSelected() FragTag=" + tab.getTag());

        // clear any displayed windows
        resetUi(true);

        // attach / replace a fragment by tag
        String tabTag = (String) tab.getTag();
        Fragment fragment = null;
        boolean replace = false;

        // search a room by name
        if (TextUtils.equals(tabTag, TAG_FRAGMENT_SEARCH_IN_ROOM_NAMES)) {
            if (null == mSearchInRoomNamesFragment) {
                replace = true;
                mSearchInRoomNamesFragment = VectorSearchRoomsListFragment.newInstance(mSession.getMyUserId(),
                        R.layout.fragment_vector_recents_list);
            }
            fragment = mSearchInRoomNamesFragment;
            mCurrentTabIndex = mSearchInRoomNamesTabIndex;

        }
        // search a message by its body
        else if (TextUtils.equals((String) tab.getTag(), TAG_FRAGMENT_SEARCH_IN_MESSAGE)) {
            if (null == mSearchInMessagesFragment) {
                replace = true;
                mSearchInMessagesFragment = VectorSearchMessagesListFragment.newInstance(mSession.getMyUserId(),
                        null, org.matrix.androidsdk.R.layout.fragment_matrix_message_list_fragment);
            }
            fragment = mSearchInMessagesFragment;
            mCurrentTabIndex = mSearchInMessagesTabIndex;
        }
        // search a file by name
        else if (TextUtils.equals((String) tab.getTag(), TAG_FRAGMENT_SEARCH_IN_FILES)) {
            if (null == mSearchInFilesFragment) {
                replace = true;
                mSearchInFilesFragment = VectorSearchRoomsFilesListFragment.newInstance(mSession.getMyUserId(),
                        null, org.matrix.androidsdk.R.layout.fragment_matrix_message_list_fragment);
            }
            fragment = mSearchInFilesFragment;
            mCurrentTabIndex = mSearchInFilesTabIndex;
        }
        // search an user by name
        else if (TextUtils.equals((String) tab.getTag(), TAG_FRAGMENT_SEARCH_PEOPLE)) {
            if (null == mSearchInPeopleFragment) {
                replace = true;
                mSearchInPeopleFragment = VectorSearchPeopleListFragment.newInstance(mSession.getMyUserId(),
                        R.layout.fragment_vector_search_people_list);
            }
            fragment = mSearchInPeopleFragment;
            mCurrentTabIndex = mSearchInPeopleTabIndex;

            // Check permission to access contacts
            CommonActivityUtils.checkPermissions(CommonActivityUtils.REQUEST_CODE_PERMISSION_MEMBERS_SEARCH, this);
        }

        if (replace) {
            ft.replace(R.id.search_fragment_container, fragment, tabTag);
        } else {
            ft.attach(fragment);
        }

        /*if (-1 != mCurrentTabIndex) {
        searchAccordingToTabHandler();
        }*/

        resetUi(true);
    }

    @Override
    public void onTabUnselected(android.support.v7.app.ActionBar.Tab tab,
            android.support.v4.app.FragmentTransaction ft) {
        String tabTag = (String) tab.getTag();
        Log.d(LOG_TAG, "## onTabUnselected() FragTag=" + tabTag);

        if (TextUtils.equals(tabTag, TAG_FRAGMENT_SEARCH_IN_MESSAGE)) {
            if (null != mSearchInMessagesFragment) {
                mSearchInMessagesFragment.cancelCatchingRequests();
                ft.detach(mSearchInMessagesFragment);
            }
        } else if (TextUtils.equals(tabTag, TAG_FRAGMENT_SEARCH_IN_ROOM_NAMES)) {
            if (null != mSearchInRoomNamesFragment) {
                ft.detach(mSearchInRoomNamesFragment);
            }
        } else if (TextUtils.equals(tabTag, TAG_FRAGMENT_SEARCH_IN_FILES)) {
            if (null != mSearchInFilesFragment) {
                mSearchInFilesFragment.cancelCatchingRequests();
                ft.detach(mSearchInFilesFragment);
            }
        } else if (TextUtils.equals(tabTag, TAG_FRAGMENT_SEARCH_PEOPLE)) {
            if (null != mSearchInPeopleFragment) {
                ft.detach(mSearchInPeopleFragment);
            }
        }
    }

    @Override
    public void onTabReselected(android.support.v7.app.ActionBar.Tab tab, FragmentTransaction ft) {
    }

    @Override
    public void onRequestPermissionsResult(int aRequestCode, @NonNull String[] aPermissions,
            @NonNull int[] aGrantResults) {
        if (0 == aPermissions.length) {
            Log.e(LOG_TAG, "## onRequestPermissionsResult(): cancelled " + aRequestCode);
        } else if (aRequestCode == CommonActivityUtils.REQUEST_CODE_PERMISSION_MEMBERS_SEARCH) {
            if (PackageManager.PERMISSION_GRANTED == aGrantResults[0]) {
                Log.d(LOG_TAG, "## onRequestPermissionsResult(): READ_CONTACTS permission granted");
            } else {
                Log.d(LOG_TAG, "## onRequestPermissionsResult(): READ_CONTACTS permission not granted");
                CommonActivityUtils.displayToast(this, getString(R.string.missing_permissions_warning));
            }
            ContactsManager.refreshLocalContactsSnapshot(this.getApplicationContext());
        }
    }

    //==============================================================================================================
    // Life cycle Activity methods
    //==============================================================================================================

    @SuppressLint("LongLogTag")
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(LOG_TAG, "## onSaveInstanceState(): ");

        // save current tab
        int currentIndex = mActionBar.getSelectedNavigationIndex();
        outState.putInt(KEY_STATE_CURRENT_TAB_INDEX, currentIndex);

        String searchPattern = mPatternToSearchEditText.getText().toString();

        if (!TextUtils.isEmpty(searchPattern)) {
            outState.putString(KEY_STATE_SEARCH_PATTERN, searchPattern);
        }
    }

    //==============================================================================================================
    // VectorBaseSearchActivity.IVectorSearchActivity
    //==============================================================================================================

    public void refreshSearch() {
        searchAccordingToTabHandler();
    }
}