Java tutorial
/** * 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; } }