Java tutorial
/* * Copyright 2014 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.neon.activity; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar.TabListener; import org.matrix.androidsdk.util.Log; import android.view.View; import android.widget.Toast; import org.matrix.androidsdk.fragments.MatrixMessageListFragment; import org.matrix.androidsdk.listeners.MXEventListener; import java.util.List; import im.neon.Matrix; import im.neon.R; import im.neon.contacts.ContactsManager; import im.neon.fragments.VectorRoomDetailsMembersFragment; import im.neon.fragments.VectorRoomSettingsFragment; import im.neon.fragments.VectorSearchRoomFilesListFragment; /** * This class implements the room details screen, using a tab UI pattern. * Each tab is filled in with its corresponding fragment. * There are 2 tabs: * - People tab: the members of the room * - Settings tab: the settings of the room */ public class VectorRoomDetailsActivity extends MXCActionBarActivity implements TabListener { private static final String LOG_TAG = "VectorRoomDetailsAct"; // exclude the room ID public static final String EXTRA_ROOM_ID = "VectorRoomDetailsActivity.EXTRA_ROOM_ID"; // open a dedicated tab at launch public static final String EXTRA_SELECTED_TAB_ID = "VectorRoomDetailsActivity.EXTRA_SELECTED_TAB_ID"; // tab related items private static final String TAG_FRAGMENT_PEOPLE_ROOM_DETAILS = "im.vector.activity.TAG_FRAGMENT_PEOPLE_ROOM_DETAILS"; private static final String TAG_FRAGMENT_FILES_DETAILS = "im.vector.activity.TAG_FRAGMENT_FILES_DETAILS"; private static final String TAG_FRAGMENT_SETTINGS_ROOM_DETAIL = "im.vector.activity.TAG_FRAGMENT_SETTINGS_ROOM_DETAIL"; private static final String KEY_FRAGMENT_TAG = "KEY_FRAGMENT_TAG"; // a tab can be selected at launch (with EXTRA_SELECTED_TAB_ID) // so the tab index must be fixed. public static final int PEOPLE_TAB_INDEX = 0; public static final int FILE_TAB_INDEX = 1; public static final int SETTINGS_TAB_INDEX = 2; private int mCurrentTabIndex = -1; private ActionBar mActionBar; private VectorRoomDetailsMembersFragment mRoomDetailsMembersFragment; private VectorSearchRoomFilesListFragment mSearchFilesFragment; private VectorRoomSettingsFragment mRoomSettingsFragment; // activity life cycle management: // - Bundle keys private static final String KEY_STATE_CURRENT_TAB_INDEX = "CURRENT_SELECTED_TAB"; // UI items private View mLoadOldestContentView; private View mWaitWhileSearchInProgressView; private String mRoomId; private String mMatrixId; // request the contacts permission private boolean mIsContactsPermissionChecked; private final MXEventListener mEventListener = new MXEventListener() { @Override public void onLeaveRoom(String roomId) { runOnUiThread(new Runnable() { @Override public void run() { // pop to the home activity Intent intent = new Intent(VectorRoomDetailsActivity.this, VectorHomeActivity.class); intent.setFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP | android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP); VectorRoomDetailsActivity.this.startActivity(intent); } }); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); 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; } Intent intent = getIntent(); if (!intent.hasExtra(EXTRA_ROOM_ID)) { Log.e(LOG_TAG, "No room ID extra."); finish(); return; } if (intent.hasExtra(EXTRA_MATRIX_ID)) { mMatrixId = intent.getStringExtra(EXTRA_MATRIX_ID); } // get current session mSession = Matrix.getInstance(getApplicationContext()).getSession(mMatrixId); if (null == mSession) { finish(); return; } mRoomId = intent.getStringExtra(EXTRA_ROOM_ID); mRoom = mSession.getDataHandler().getRoom(mRoomId); int selectedTab = intent.getIntExtra(EXTRA_SELECTED_TAB_ID, -1); setContentView(R.layout.activity_vector_room_details); // UI widgets binding & init fields mWaitWhileSearchInProgressView = findViewById(R.id.settings_loading_layout); mLoadOldestContentView = findViewById(R.id.search_load_oldest_progress); // tab creation and restore tabs UI context mActionBar = getSupportActionBar(); createNavigationTabs(savedInstanceState, selectedTab); } @Override protected void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); List<android.support.v4.app.Fragment> allFragments = getSupportFragmentManager().getFragments(); // dispatch the result to each fragments for (android.support.v4.app.Fragment fragment : allFragments) { fragment.onActivityResult(requestCode, resultCode, data); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.d(LOG_TAG, "## onSaveInstanceState(): "); // save current tab if (null != mActionBar) { int currentIndex = mActionBar.getSelectedNavigationIndex(); outState.putInt(KEY_STATE_CURRENT_TAB_INDEX, currentIndex); } } @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_MEMBER_DETAILS) { if (Manifest.permission.READ_CONTACTS.equals(aPermissions[0])) { if (PackageManager.PERMISSION_GRANTED == aGrantResults[0]) { Log.d(LOG_TAG, "## onRequestPermissionsResult(): READ_CONTACTS permission granted"); } else { Log.w(LOG_TAG, "## onRequestPermissionsResult(): READ_CONTACTS permission not granted"); CommonActivityUtils.displayToast(this, getString(R.string.missing_permissions_warning)); } ContactsManager.getInstance().refreshLocalContactsSnapshot(); } } } /** * Back key management */ public void onBackPressed() { boolean isTrapped = false; if (PEOPLE_TAB_INDEX == mCurrentTabIndex) { isTrapped = mRoomDetailsMembersFragment.onBackPressed(); } if (!isTrapped) { super.onBackPressed(); } } @Override protected void onPause() { super.onPause(); // listen for room leave event mRoom.removeEventListener(mEventListener); } @Override protected void onResume() { super.onResume(); if (mSession.isAlive()) { // check if the room has been left from another client if ((null == mRoom.getMember(mSession.getMyUserId())) || !mSession.getDataHandler().doesRoomExist(mRoom.getRoomId())) { // pop to the home activity Intent intent = new Intent(VectorRoomDetailsActivity.this, VectorHomeActivity.class); intent.setFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP | android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP); VectorRoomDetailsActivity.this.startActivity(intent); return; } // listen for room leave event mRoom.addEventListener(mEventListener); // start the file search if the selected tab is the file one startFileSearch(); } } /** * Update the tag of the tab with its the UI values * * @param aTabToUpdate the tab to be updated */ private void saveUiTabContext(ActionBar.Tab aTabToUpdate) { Bundle tabTag = (Bundle) aTabToUpdate.getTag(); aTabToUpdate.setTag(tabTag); } /** * Reset the UI to its init state: * - "waiting while searching" screen disabled * - background image visible * - no results message disabled */ private void resetUi() { // stop "wait while searching" screen if (null != mWaitWhileSearchInProgressView) { mWaitWhileSearchInProgressView.setVisibility(View.GONE); } if (null != mLoadOldestContentView) { mLoadOldestContentView.setVisibility(View.GONE); } } // ============================================================================================= // Tabs logic implementation private void createNavigationTabs(Bundle aSavedInstanceState, int defaultSelectedTab) { int tabIndexToRestore; // Set the tabs navigation mode mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // People tab creation: display the members of the this room ActionBar.Tab tabToBeAdded = mActionBar.newTab(); String tabTitle = getResources().getString(R.string.room_details_people); tabToBeAdded.setText(tabTitle); tabToBeAdded.setTabListener(this); Bundle tabBundle = new Bundle(); tabBundle.putString(KEY_FRAGMENT_TAG, TAG_FRAGMENT_PEOPLE_ROOM_DETAILS); tabToBeAdded.setTag(tabBundle); mActionBar.addTab(tabToBeAdded); // Files tab creation: display the file list in the room history tabToBeAdded = mActionBar.newTab(); tabTitle = getResources().getString(R.string.room_details_files); tabToBeAdded.setText(tabTitle); tabToBeAdded.setTabListener(this); tabBundle = new Bundle(); tabBundle.putString(KEY_FRAGMENT_TAG, TAG_FRAGMENT_FILES_DETAILS); tabToBeAdded.setTag(tabBundle); mActionBar.addTab(tabToBeAdded); // Settings tab creation: the room settings (room photo, name, topic..) tabToBeAdded = mActionBar.newTab(); tabTitle = getResources().getString(R.string.room_details_settings); tabToBeAdded.setText(tabTitle); tabToBeAdded.setTabListener(this); tabBundle = new Bundle(); tabBundle.putString(KEY_FRAGMENT_TAG, TAG_FRAGMENT_SETTINGS_ROOM_DETAIL); tabToBeAdded.setTag(tabBundle); mActionBar.addTab(tabToBeAdded); // set the default tab to be displayed tabIndexToRestore = (null != aSavedInstanceState) ? aSavedInstanceState.getInt(KEY_STATE_CURRENT_TAB_INDEX, -1) : -1; if (-1 == tabIndexToRestore) { tabIndexToRestore = defaultSelectedTab; } if (-1 == tabIndexToRestore) { // default value: display the search in rooms tab tabIndexToRestore = PEOPLE_TAB_INDEX; } mActionBar.setStackedBackgroundDrawable( new ColorDrawable(getResources().getColor(R.color.vector_tabbar_background_color))); // set the tab to display & set current tab index mActionBar.setSelectedNavigationItem(tabIndexToRestore); mCurrentTabIndex = tabIndexToRestore; } /** * Called when a tab enters the selected state. * * @param tab The tab that was selected * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute * during a tab switch. The previous tab's unselected and this tab's select will be * executed in a single transaction. This FragmentTransaction does not support */ @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { Bundle tabHolder = (Bundle) tab.getTag(); String fragmentTag = tabHolder.getString(KEY_FRAGMENT_TAG, ""); Log.d(LOG_TAG, "## onTabSelected() FragTag=" + fragmentTag); resetUi(); if (fragmentTag.equals(TAG_FRAGMENT_PEOPLE_ROOM_DETAILS)) { mRoomDetailsMembersFragment = (VectorRoomDetailsMembersFragment) getSupportFragmentManager() .findFragmentByTag(TAG_FRAGMENT_PEOPLE_ROOM_DETAILS); if (null == mRoomDetailsMembersFragment) { mRoomDetailsMembersFragment = VectorRoomDetailsMembersFragment.newInstance(); ft.replace(R.id.room_details_fragment_container, mRoomDetailsMembersFragment, TAG_FRAGMENT_PEOPLE_ROOM_DETAILS); Log.d(LOG_TAG, "## onTabSelected() people frag replace"); } else { ft.attach(mRoomDetailsMembersFragment); Log.d(LOG_TAG, "## onTabSelected() people frag attach"); } mCurrentTabIndex = PEOPLE_TAB_INDEX; if (!mIsContactsPermissionChecked) { mIsContactsPermissionChecked = true; CommonActivityUtils.checkPermissions(CommonActivityUtils.REQUEST_CODE_PERMISSION_MEMBER_DETAILS, this); } } else if (fragmentTag.equals(TAG_FRAGMENT_SETTINGS_ROOM_DETAIL)) { int permissionToBeGranted = CommonActivityUtils.REQUEST_CODE_PERMISSION_ROOM_DETAILS; onTabSelectSettingsFragment(); // remove camera permission request if the user has not enough power level if (!CommonActivityUtils.isPowerLevelEnoughForAvatarUpdate(mRoom, mSession)) { permissionToBeGranted &= ~CommonActivityUtils.PERMISSION_CAMERA; } CommonActivityUtils.checkPermissions(permissionToBeGranted, this); mCurrentTabIndex = SETTINGS_TAB_INDEX; } else if (fragmentTag.equals(TAG_FRAGMENT_FILES_DETAILS)) { mSearchFilesFragment = (VectorSearchRoomFilesListFragment) getSupportFragmentManager() .findFragmentByTag(TAG_FRAGMENT_FILES_DETAILS); if (null == mSearchFilesFragment) { mSearchFilesFragment = VectorSearchRoomFilesListFragment.newInstance( mSession.getCredentials().userId, mRoomId, org.matrix.androidsdk.R.layout.fragment_matrix_message_list_fragment); ft.replace(R.id.room_details_fragment_container, mSearchFilesFragment, TAG_FRAGMENT_FILES_DETAILS); Log.d(LOG_TAG, "## onTabSelected() file frag replace"); } else { ft.attach(mSearchFilesFragment); Log.d(LOG_TAG, "## onTabSelected() file frag attach"); } mCurrentTabIndex = FILE_TAB_INDEX; startFileSearch(); } else { Toast.makeText(this, "Not yet implemented", Toast.LENGTH_SHORT).show(); mCurrentTabIndex = SETTINGS_TAB_INDEX; Log.w(LOG_TAG, "## onTabSelected() unknown tab selected!!"); } // reset the activity title // some fragments update it (VectorRoomDetailsMembersFragment for example) if (null != getSupportActionBar()) { getSupportActionBar().setTitle(this.getResources().getString(R.string.room_details_title)); } } /** * Start a file search */ private void startFileSearch() { if (mCurrentTabIndex == FILE_TAB_INDEX) { mWaitWhileSearchInProgressView.setVisibility(View.VISIBLE); mSearchFilesFragment.startFilesSearch(new MatrixMessageListFragment.OnSearchResultListener() { @Override public void onSearchSucceed(int nbrMessages) { onSearchEnd(FILE_TAB_INDEX, nbrMessages); } @Override public void onSearchFailed() { onSearchEnd(FILE_TAB_INDEX, 0); } }); } } /** * 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); } } /** * Called when a tab exits the selected state. * * @param tab The tab that was unselected * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute * during a tab switch. This tab's unselected and the newly selected tab's select * will be executed in a single transaction. This FragmentTransaction does not */ @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { Bundle tabHolder = (Bundle) tab.getTag(); String fragmentTag = tabHolder.getString(KEY_FRAGMENT_TAG, ""); Log.d(LOG_TAG, "## onTabUnselected() FragTag=" + fragmentTag); // save tab UI context before leaving the tab... saveUiTabContext(tab); if (fragmentTag.equals(TAG_FRAGMENT_PEOPLE_ROOM_DETAILS)) { if (null != mRoomDetailsMembersFragment) { ft.detach(mRoomDetailsMembersFragment); } } else if (fragmentTag.equals(TAG_FRAGMENT_SETTINGS_ROOM_DETAIL)) { onTabUnselectedSettingsFragment(); } else if (fragmentTag.equals(TAG_FRAGMENT_FILES_DETAILS)) { if (null != mSearchFilesFragment) { mSearchFilesFragment.cancelCatchingRequests(); ft.detach(mSearchFilesFragment); } } else { Log.w(LOG_TAG, "## onTabUnselected() unknown tab selected!!"); } } /** * Called when a tab that is already selected is chosen again by the user. * Some applications may use this action to return to the top level of a category. * * @param tab The tab that was reselected. * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute * once this method returns. This FragmentTransaction does not support */ @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { } /** * Specific method to add the fragment, to avoid using the FragmentTransaction * that requires a Fragment based on the support V4. */ private void onTabSelectSettingsFragment() { runOnUiThread(new Runnable() { @Override public void run() { if (null == mRoomSettingsFragment) { mRoomSettingsFragment = VectorRoomSettingsFragment.newInstance(mMatrixId, mRoomId); getFragmentManager().beginTransaction().replace(R.id.room_details_fragment_container, mRoomSettingsFragment, TAG_FRAGMENT_SETTINGS_ROOM_DETAIL).commit(); Log.d(LOG_TAG, "## onTabSelectSettingsFragment() settings frag replace"); } else { getFragmentManager().beginTransaction().attach(mRoomSettingsFragment).commit(); Log.d(LOG_TAG, "## onTabSelectSettingsFragment() settings frag attach"); } } }); } /** * Specific method to add the fragment, to avoid using the FragmentTransaction * that requires a Fragment based on the support V4. */ private void onTabUnselectedSettingsFragment() { runOnUiThread(new Runnable() { @Override public void run() { if (null != mRoomSettingsFragment) getFragmentManager().beginTransaction().detach(mRoomSettingsFragment).commit(); } }); } // ========================================================================================== }