com.treefrogapps.friendlychat.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.treefrogapps.friendlychat.MainActivity.java

Source

/**
 * Copyright Google Inc. All Rights Reserved.
 * <p/>
 * 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
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * 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 com.treefrogapps.friendlychat;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;

import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.BuildConfig;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.google.friendlychat.R;

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

import static android.widget.Toast.LENGTH_SHORT;
import static android.widget.Toast.makeText;
import static java.util.Arrays.asList;

public class MainActivity extends AppCompatActivity {

    private static final String[] PERMISSIONS = new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE };
    private static final String MESSAGES_DATA = "messages";
    private static final String PHOTOS_DATA = "chat_photos";
    private static final int REQUEST_CODE_PERMISSIONS = 5;
    private static final int REQUEST_CODE_PHOTO = 10;
    private static final int REQUEST_CODE_AUTH = 20;
    public static final String ANONYMOUS = "test_anonymous_user";
    public static final int MAX_MESSAGE_LENGTH = 300;
    private static final String MESSAGE_DEFAULT_MAX_LENGTH = "max_message_length";

    private MessageAdapter mMessageAdapter;
    private ProgressBar mProgressBar;
    private EditText mMessageEditText;
    private Button mSendButton;

    private String mUsername = ANONYMOUS;
    //Firebase
    private FirebaseDatabase firebaseDatabase;
    private DatabaseReference messagesDatabaseReference;
    private ChildEventListener childEventListener;
    private FirebaseAuth firebaseAuth;
    private FirebaseAuth.AuthStateListener stateListener;
    private FirebaseStorage firebaseStorage;
    private StorageReference storageReference;
    private OnSuccessListener<UploadTask.TaskSnapshot> uploadSuccessListener;
    private OnFailureListener uploadFailureListener;
    private FirebaseRemoteConfig firebaseRemoteConfig;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize references to views
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        ListView mMessageListView = (ListView) findViewById(R.id.messageListView);
        ImageButton mPhotoPickerButton = (ImageButton) findViewById(R.id.photoPickerButton);
        mMessageEditText = (EditText) findViewById(R.id.messageEditText);
        mSendButton = (Button) findViewById(R.id.sendButton);

        // Initialize message ListView and its adapter
        List<FriendlyMessage> friendlyMessages = new ArrayList<>();
        mMessageAdapter = new MessageAdapter(this, R.layout.item_message, friendlyMessages);
        mMessageListView.setAdapter(mMessageAdapter);

        // Initialize progress bar
        mProgressBar.setVisibility(ProgressBar.INVISIBLE);

        //Firebase
        firebaseDatabase = FirebaseDatabase.getInstance();
        messagesDatabaseReference = firebaseDatabase.getReference().child(MESSAGES_DATA);

        firebaseStorage = FirebaseStorage.getInstance();
        storageReference = firebaseStorage.getReference().child(PHOTOS_DATA);
        uploadSuccessListener = taskSnapshot -> messagesDatabaseReference.push()
                .setValue(new FriendlyMessage(null, mUsername, taskSnapshot.getDownloadUrl().toString()));
        uploadFailureListener = Exception::printStackTrace;

        firebaseAuth = FirebaseAuth.getInstance();
        stateListener = firebaseAuth -> {
            if (firebaseAuth.getCurrentUser() != null) {
                Log.i(getClass().getSimpleName(), "Auth state callback - signed in");
                onSignedIn(firebaseAuth.getCurrentUser());
            } else {
                onSignedOut();
                signInUser();
            }
        };

        firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
        FirebaseRemoteConfigSettings settings = new FirebaseRemoteConfigSettings.Builder()
                .setDeveloperModeEnabled(BuildConfig.DEBUG).build();
        firebaseRemoteConfig.setConfigSettings(settings);
        Map<String, Object> defaultConfig = new HashMap<>();
        defaultConfig.put(MESSAGE_DEFAULT_MAX_LENGTH, MAX_MESSAGE_LENGTH);
        firebaseRemoteConfig.setDefaults(defaultConfig);
        fetchRemoteSettings();

        // ImagePickerButton shows an image picker to upload a image for a message
        mPhotoPickerButton.setOnClickListener(this::startImageBrowser);

        // Enable Send button when there's text to send
        mMessageEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                if (charSequence.toString().trim().length() > 0) {
                    mSendButton.setEnabled(true);
                } else {
                    mSendButton.setEnabled(false);
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {
            }
        });

        // Send button sends a message and clears the EditText
        mSendButton.setOnClickListener(view -> {
            if (mMessageEditText.getText().toString().length() > 0) {
                FriendlyMessage message = new FriendlyMessage(mMessageEditText.getText().toString(), mUsername,
                        null);
                messagesDatabaseReference.push().setValue(message);
                // Clear input box
                mMessageEditText.setText("");
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();

        //Firebase
        firebaseAuth.addAuthStateListener(stateListener);
    }

    @Override
    protected void onPause() {
        super.onPause();

        //Firebase
        firebaseAuth.removeAuthStateListener(stateListener);
        detachDatabaseListener();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stateListener = null;
        uploadSuccessListener = null;
        uploadFailureListener = null;
    }

    @SuppressWarnings("ConstantConditions")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        mProgressBar.setVisibility(ProgressBar.INVISIBLE);
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
            case REQUEST_CODE_PHOTO:
                uploadToFirebase(data.getData());
                break;
            case REQUEST_CODE_AUTH:
                makeText(this, "Welcome " + firebaseAuth.getCurrentUser().getDisplayName(), LENGTH_SHORT);
                break;
            default:
                break;
            }
        } else if (resultCode == RESULT_CANCELED) {
            makeText(this, "Operation cancelled", LENGTH_SHORT).show();
            if (requestCode == REQUEST_CODE_AUTH)
                finish();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.sign_out_menu:
            if (firebaseAuth.getCurrentUser() != null) {
                AuthUI.getInstance().signOut(this);
            }
            return true;
        default:
            return super.onOptionsItemSelected(item);

        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        boolean hasPermissions = true;
        if (requestCode == REQUEST_CODE_PERMISSIONS) {
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    hasPermissions = false;
                    break;
                }
            }
            if (hasPermissions) {
                startImageBrowser(null);
            }
        }
    }

    private void fetchRemoteSettings() {
        long settingsCacheTimeout = firebaseRemoteConfig.getInfo().getConfigSettings().isDeveloperModeEnabled() ? 0
                : 3600;
        firebaseRemoteConfig.fetch(settingsCacheTimeout).addOnSuccessListener(this::updateInputFilter)
                .addOnFailureListener(this::updateInputFilter);

    }

    private void updateInputFilter(Exception e) {
        Log.e(getClass().getSimpleName(), "Error getting Config");
        applyFilterSettingChange(false);
    }

    private void updateInputFilter(Void aVoid) {
        firebaseRemoteConfig.activateFetched();
        applyFilterSettingChange(true);
    }

    private void applyFilterSettingChange(boolean isRemoteSetting) {
        Long maxCharLength = firebaseRemoteConfig.getLong(MESSAGE_DEFAULT_MAX_LENGTH);
        Log.i(getClass().getSimpleName(),
                "Settings from Remote : " + isRemoteSetting + " - " + maxCharLength.intValue());
        mMessageEditText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxCharLength.intValue()) });
    }

    private void signInUser() {
        startActivityForResult(
                AuthUI.getInstance().createSignInIntentBuilder().setIsSmartLockEnabled(false)
                        .setProviders(asList(new AuthUI.IdpConfig.Builder(AuthUI.EMAIL_PROVIDER).build(),
                                new AuthUI.IdpConfig.Builder(AuthUI.GOOGLE_PROVIDER).build()))
                        .build(),
                REQUEST_CODE_AUTH);

        mProgressBar.setVisibility(ProgressBar.VISIBLE);
    }

    private void onSignedIn(FirebaseUser currentUser) {
        mUsername = currentUser.getDisplayName() != null ? currentUser.getDisplayName() : ANONYMOUS;
        attachDatabaseListener();
    }

    private void attachDatabaseListener() {
        if (childEventListener == null) {
            childEventListener = new ChildEventListener() {
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                    FriendlyMessage message = dataSnapshot.getValue(FriendlyMessage.class);
                    mMessageAdapter.add(message);
                }

                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                }

                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) {
                }

                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) {
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                }
            };
            messagesDatabaseReference.addChildEventListener(childEventListener);
        }
    }

    private void onSignedOut() {
        mUsername = ANONYMOUS;
        detachDatabaseListener();
    }

    private void detachDatabaseListener() {
        if (childEventListener != null) {
            messagesDatabaseReference.removeEventListener(childEventListener);
            childEventListener = null;
            mMessageAdapter.clear();
        }
    }

    private Intent createChooserIntent(String mimeType) {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType(mimeType);
        return intent;
    }

    private void startImageBrowser(View view) {
        if (havePermissions()) {
            Intent intent = createChooserIntent("image/*");
            startActivityForResult(intent, REQUEST_CODE_PHOTO);
        } else {
            ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_CODE_PERMISSIONS);
        }
    }

    private void uploadToFirebase(Uri imageUri) {
        StorageReference reference = storageReference.child(imageUri.getLastPathSegment());
        reference.putFile(imageUri).addOnSuccessListener(uploadSuccessListener)
                .addOnFailureListener(uploadFailureListener);
    }

    private boolean havePermissions() {
        return ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(this,
                        Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
    }
}