com.ferid.app.frequentcontacts.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.ferid.app.frequentcontacts.MainActivity.java

Source

/*
 * Copyright (C) 2014 Ferid Cafer
 *
 * 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 com.ferid.app.frequentcontacts;

import android.Manifest;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Base64;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.TextView;

import com.ferid.app.frequentcontacts.interfaces.ItemClickListener;
import com.ferid.app.frequentcontacts.list.Contact;
import com.ferid.app.frequentcontacts.list.ContactsAdapter;
import com.ferid.app.frequentcontacts.prefs.PrefsUtil;
import com.ferid.app.frequentcontacts.selectnumber.SelectNumberActivity;
import com.ferid.app.frequentcontacts.widget.FrequentContactsWidget;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

/**
 * Created by ferid.cafer on 11/10/2014.
 */
public class MainActivity extends AppCompatActivity implements ItemClickListener {
    private Context context;

    private GridView list;
    private ArrayList<Contact> contactsList = new ArrayList<>();
    private ContactsAdapter adapter;

    private FloatingActionButton actionButtonAdd;

    private Contact contact = new Contact();

    private final int SELECT_NUMBER = 0;

    //photo
    private static int RESULT_LOAD_IMAGE = 1;

    //permissions
    private static int REQUEST_PERMISSIONS = 100;

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

        context = this;

        final Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        list = findViewById(R.id.list);
        adapter = new ContactsAdapter(context, R.layout.contacts_row, contactsList);
        list.setAdapter(adapter);

        TextView emptyText = findViewById(R.id.emptyText);
        list.setEmptyView(emptyText);

        actionButtonAdd = findViewById(R.id.actionButtonAdd);
        actionButtonAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                addNewContact();
            }
        });

        setListItemClickListener();

        askForPermissions();
    }

    /**
     * Set list view item click listener
     */
    private void setListItemClickListener() {
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (contactsList != null && contactsList.size() > position) {
                    contact = contactsList.get(position);

                    callContact();
                }
            }
        });
    }

    /**
     * Menu to select operation, on click on any contact item
     * @param contactPosition Position of selected contact
     * @param menuItemPosition Position of menu item
     */
    @Override
    public void OnItemClick(int contactPosition, int menuItemPosition) {
        if (contactsList != null && contactsList.size() > contactPosition) {
            contact = contactsList.get(contactPosition);

            if (menuItemPosition == 0) {
                selectPhoto();
            } else if (menuItemPosition == 1) {
                removeCurrentContact();
            }
        }
    }

    /**
     * Save data and refresh the list
     */
    private void save_refresh() {
        PrefsUtil.writeFrequentContacts(context, contactsList);
        adapter.notifyDataSetChanged();

        updateFrequentContactsWidget();
    }

    /**
     * Select a photo from the gallery
     */
    private void selectPhoto() {
        Intent intent = new Intent(Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(intent, RESULT_LOAD_IMAGE);
    }

    /**
     * Adds a new contact to the application list.<br />
     * Contacts are selected from the phone's contats' list.
     */
    private void addNewContact() {
        if (contactsList != null) {
            if (contactsList.size() < getResources().getInteger(R.integer.maxContactSize)) {
                Intent intent = new Intent(context, SelectNumberActivity.class);
                startActivityForResult(intent, SELECT_NUMBER);
                overridePendingTransition(R.anim.move_in_from_bottom, R.anim.stand_still);
            } else {
                //alert
                final AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setMessage(context.getString(R.string.maxContactsNumber));
                builder.setPositiveButton(context.getString(R.string.ok), new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
                AlertDialog alertDialog = builder.create();
                alertDialog.show();
            }
        }
    }

    /**
     * Removes a current contact from the application list.<br />
     * The contact is not removed from the phone's contacts' list.
     */
    private void removeCurrentContact() {
        contactsList.remove(contact);
        save_refresh();
    }

    /**
     * Call the selected contact
     */
    private void callContact() {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) { //if permission is already granted

            Intent callIntent = new Intent(Intent.ACTION_CALL);
            callIntent.setData(Uri.parse("tel:" + contact.getNumber()));
            startActivity(callIntent);
        }
    }

    /**
     * Updates frequent contacts widget
     */
    private void updateFrequentContactsWidget() {
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        ComponentName thisAppWidget = new ComponentName(context.getPackageName(), this.getClass().getName());
        Intent updateWidget = new Intent(context, FrequentContactsWidget.class);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
        updateWidget.setAction(FrequentContactsWidget.APP_TO_WID);
        updateWidget.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
        context.sendBroadcast(updateWidget);
    }

    /**
     * Needed for orientation of selected photo
     * @param context
     * @param photoUri
     * @return
     */
    private static int getOrientation(Context context, Uri photoUri) {
        int orientation = -1;

        /* it's on the external media. */
        Cursor cursor = context.getContentResolver().query(photoUri,
                new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

        if (cursor != null) {
            if (cursor.getCount() != 1) {
                return orientation;
            }

            cursor.moveToFirst();

            orientation = cursor.getInt(0);
            cursor.close();
        }

        return orientation;
    }

    /**
     * Get contacts list and show add button after permissions granted
     */
    private void initAfterPermissions() {
        ArrayList<Contact> result = PrefsUtil.readFrequentContacts(context);
        if (result != null) {
            contactsList.addAll(result);
        } else {
            contactsList.clear();
        }

        adapter.notifyDataSetChanged();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                actionButtonAdd.show();
            }
        }, 400);
    }

    /**
     * Ask for reading contacts and phone calling permissions
     */
    private void askForPermissions() {
        if ((ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED)
                || (ContextCompat.checkSelfPermission(this,
                        Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED)) { //permissions yet to be granted

            getPermissions();
        } else { //permissions already granted
            initAfterPermissions();
        }
    }

    /**
     * Request and get the permission for reading contacts and phone calling
     */
    private void getPermissions() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)
                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CALL_PHONE)) {

            Snackbar.make(actionButtonAdd, R.string.grantPermission, Snackbar.LENGTH_LONG)
                    .setAction(R.string.ok, new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            ActivityCompat.requestPermissions(MainActivity.this, new String[] {
                                    Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE },
                                    REQUEST_PERMISSIONS);
                        }
                    }).show();
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[] { Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE },
                    REQUEST_PERMISSIONS);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {

        if (requestCode == REQUEST_PERMISSIONS) {
            if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED) {

                //permission granted
                initAfterPermissions();
            } else {
                //permission denied
                finish();
            }
        }
    }

    /**
     * After photo process return
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == RESULT_LOAD_IMAGE) {
            //a photo picked from the gallery
            if (resultCode == RESULT_OK) {
                try {
                    Uri photoUri = data.getData();

                    InputStream is = this.getContentResolver().openInputStream(photoUri);
                    BitmapFactory.Options dbo = new BitmapFactory.Options();
                    dbo.inJustDecodeBounds = true;
                    BitmapFactory.decodeStream(is, null, dbo);
                    if (is != null)
                        is.close();

                    int rotatedWidth, rotatedHeight;
                    int orientation = getOrientation(this, photoUri);

                    if (orientation == 90 || orientation == 270) {
                        rotatedWidth = dbo.outHeight;
                        rotatedHeight = dbo.outWidth;
                    } else {
                        rotatedWidth = dbo.outWidth;
                        rotatedHeight = dbo.outHeight;
                    }

                    Bitmap srcBitmap;
                    is = this.getContentResolver().openInputStream(photoUri);
                    int MAX_IMAGE_HEIGHT = 250;
                    int MAX_IMAGE_WIDTH = 250;
                    if (rotatedWidth > MAX_IMAGE_WIDTH || rotatedHeight > MAX_IMAGE_HEIGHT) {
                        float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_WIDTH);
                        float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_HEIGHT);
                        float maxRatio = Math.max(widthRatio, heightRatio);

                        // Create the bitmap from file
                        BitmapFactory.Options options = new BitmapFactory.Options();
                        options.inSampleSize = (int) maxRatio;
                        srcBitmap = BitmapFactory.decodeStream(is, null, options);
                    } else {
                        srcBitmap = BitmapFactory.decodeStream(is);
                    }
                    if (is != null)
                        is.close();

                    //if the orientation is not 0 (or -1, which means we don't know), we have to do a rotation.
                    if (orientation > 0) {
                        Matrix matrix = new Matrix();
                        matrix.postRotate(orientation);

                        srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                                srcBitmap.getHeight(), matrix, true);
                    }

                    //srcBitmap is ready now
                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    srcBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                    byte[] byteArray = stream.toByteArray();

                    // byte[] to String convert.
                    String encodedImage = Base64.encodeToString(byteArray, Base64.DEFAULT);

                    //anti-memory leak
                    srcBitmap.recycle();

                    //ready to set photo
                    contact.setPhoto(encodedImage);
                    save_refresh();

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else if (requestCode == SELECT_NUMBER) {
            //a contact selected from the list
            if (resultCode == RESULT_OK) {
                try {
                    Contact contact = (Contact) data.getSerializableExtra("contact");
                    if (contact != null) {
                        contactsList.add(contact);
                        save_refresh();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}