Android Open Source - DoorCodeNotifier Address Info List Activity






From Project

Back to project page DoorCodeNotifier.

License

The source code is released under:

GNU General Public License

If you think the Android project DoorCodeNotifier listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * This source is part of the//  w w w.  j  av  a 2s. co  m
 *      _____  ___   ____
 *  __ / / _ \/ _ | / __/___  _______ _
 * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/
 * \___/_/|_/_/ |_/_/ (_)___/_/  \_, /
 *                              /___/
 * repository.
 *
 * Copyright (C) 2015 Benoit 'BoD' Lubek (BoD@JRAF.org)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.jraf.android.dcn.handheld.app.addressinfo.list;

import android.animation.Animator;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SwitchCompat;
import android.view.Display;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;

import org.jraf.android.dcn.BuildConfig;
import org.jraf.android.dcn.R;
import org.jraf.android.dcn.handheld.Constants;
import org.jraf.android.dcn.handheld.app.addressinfo.edit.AddressInfoEditActivity;
import org.jraf.android.dcn.handheld.app.geofencing.GeofencingService;
import org.jraf.android.dcn.handheld.model.addressinfo.AddressInfo;
import org.jraf.android.dcn.handheld.util.picasso.location.LocationUtil;
import org.jraf.android.util.about.AboutActivityIntentBuilder;
import org.jraf.android.util.async.Task;
import org.jraf.android.util.async.TaskFragment;
import org.jraf.android.util.dialog.AlertDialogFragment;
import org.jraf.android.util.dialog.AlertDialogListener;
import org.jraf.android.util.log.wrapper.Log;
import org.jraf.android.util.string.StringUtil;
import org.jraf.android.util.ui.UiUtil;

import java.util.ArrayList;

import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;


public class AddressInfoListActivity extends ActionBarActivity implements AlertDialogListener, AddressInfoCallbacks {
    private static final int REQUEST_CONTACT_PICK = 0;
    private static final int REQUEST_INSTALL_PLAY_SERVICES = 1;

    private static final int DIALOG_CHOOSE_ADDRESS_TO_EDIT = 0;
    private static final int DIALOG_LOCATION_SETTINGS = 1;

    @InjectView(R.id.conFencingDisabled)
    protected View mConGeofencingDisabled;

    @InjectView(R.id.imgArrowUp)
    protected View mImgArrowUp;

    private SwitchCompat mSwiGeofencing;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.addressinfo_list);
        ButterKnife.inject(this);

        // Custom action bar that contains the "done" button for saving changes
        ActionBar actionBar = getSupportActionBar();
        @SuppressLint("InflateParams") View customActionBarView = getLayoutInflater().inflate(R.layout.addressinfo_list_actionbar, null);
        mSwiGeofencing = (SwitchCompat) customActionBarView.findViewById(R.id.swiGeofencing);
        // Check it if enabled in prefs
        SharedPreferences preferenceManager = PreferenceManager.getDefaultSharedPreferences(this);
        final boolean enabled = preferenceManager.getBoolean(Constants.PREF_GEOFENCING_ENABLED, Constants.PREF_GEOFENCING_ENABLED_DEFAULT);
        mSwiGeofencing.setChecked(enabled);
        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams(Gravity.CENTER_VERTICAL | Gravity.RIGHT));

        // Align the up arrow with the switch - this needs to be done in a viewTreeObserver otherwise it is too early
        final View contentView = findViewById(android.R.id.content);
        contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public int mViewTreeObserverCount = 0;

            @Override
            public void onGlobalLayout() {
                // The first call is too early, the switch hasn't been laid out yet, so do this only the second time
                if (mViewTreeObserverCount > 0) {
                    // Show disabled indicator if needed
                    if (enabled) {
                        mConGeofencingDisabled.setVisibility(View.GONE);
                    } else {
                        alignUpArrow(); mConGeofencingDisabled.setVisibility(View.VISIBLE);
                    }
                }

                mViewTreeObserverCount++;
                // Unregister self
                if (mViewTreeObserverCount == 2) contentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Check for Google Play Services
        int res = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (res != ConnectionResult.SUCCESS) {
            Dialog dialog = GooglePlayServicesUtil.getErrorDialog(res, this, REQUEST_INSTALL_PLAY_SERVICES, new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    finish();
                }
            }); dialog.show();
        }

        // Check for location settings
        if (!LocationUtil.isLocationEnabled(this)) {
            AlertDialogFragment dialog = AlertDialogFragment.newInstance(DIALOG_LOCATION_SETTINGS);
            dialog.setMessage(R.string.addressInfo_list_locationDialog_message); dialog.setPositiveButton(R.string.addressInfo_list_locationDialog_positive);
            dialog.setNegativeButton(R.string.addressInfo_list_locationDialog_negative); dialog.show(getSupportFragmentManager());
        }
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_about: onAboutClicked(); return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @OnClick(R.id.btnAdd)
    protected void onAddClicked() {
        // For some unknown reason, when starting the contact list activity with ACTION_PICK, the "create new contact" button
        // is hidden.  It is visible when starting with ACTION_GET_CONTENT.
        // Because of this, we first find which component deals with ACTION_PICK, but then start it with ACTION_GET_CONTENT.
        PackageManager packageManager = getPackageManager();
        Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
        ResolveInfo resolveInfo = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);

        intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
        // Explicitly set the component found above
        intent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));
        intent.putExtra("finishActivityOnSaveCompleted", true); // see http://developer.android.com/training/contacts-provider/modify-data.html

        startActivityForResult(intent, REQUEST_CONTACT_PICK);
    }

    private void onAboutClicked() {
        AboutActivityIntentBuilder builder = new AboutActivityIntentBuilder(); builder.setAppName(getString(R.string.app_name));
        builder.setBuildDate(BuildConfig.BUILD_DATE); builder.setGitSha1(BuildConfig.GIT_SHA1);
        builder.setAuthorCopyright(getString(R.string.about_authorCopyright)); builder.setLicense(getString(R.string.about_License));
        builder.setShareTextSubject(getString(R.string.about_shareText_subject)); builder.setShareTextBody(getString(R.string.about_shareText_body));
        builder.setBackgroundResId(R.drawable.about_bg); builder.addLink(getString(R.string.about_email_uri), getString(R.string.about_email_text));
        builder.addLink(getString(R.string.about_web_uri), getString(R.string.about_web_text));
        builder.addLink(getString(R.string.about_sources_uri), getString(R.string.about_sources_text)); builder.setIsLightIcons(true);
        startActivity(builder.build(this));
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CONTACT_PICK:
                if (resultCode != RESULT_OK) break;
                Log.d("data=" + StringUtil.toString(data));
                Uri contactLookupUri = data.getData();
                checkForMultipleAddresses(contactLookupUri);
                break;

            default:
                super.onActivityResult(requestCode, resultCode, data);
                break;
        }
    }

    private static class StructuredPostal {
        Uri uri;
        String formattedAddress;
    }

    private void checkForMultipleAddresses(final Uri contactLookupUri) {
        Log.d();
        new TaskFragment(new Task<AddressInfoListActivity>() {
            @Override
            protected void doInBackground() throws Throwable {
                // 1/ Find the contact id from the contact lookup uri
                String[] projection = {ContactsContract.Contacts._ID};
                AddressInfoListActivity a = getActivity();
                Cursor c = a.getContentResolver().query(contactLookupUri, projection, null, null, null);
                long contactId = 0;
                try {
                    if (c.moveToNext()) {
                        contactId = c.getLong(0);
                    } else {
                        // TODO Handle error case
                    }
                } finally {
                    c.close();
                }

                // 2/ Find addresses for this contact
                ArrayList<StructuredPostal> structuredPostalList = new ArrayList<>(); projection = new String[] {ContactsContract.Data._ID, // 0
                        ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, // 1
                };
                String selection = ContactsContract.Contacts.Data.MIMETYPE + "=? AND " + ContactsContract.Data.CONTACT_ID + "=?";
                String[] selectionArg = {ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE, String.valueOf(contactId)};
                c = a.getContentResolver().query(ContactsContract.Data.CONTENT_URI, projection, selection, selectionArg, null);
                try {
                    while (c.moveToNext()) {
                        StructuredPostal structuredPostal = new StructuredPostal();
                        structuredPostal.uri = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, c.getLong(0));
                        structuredPostal.formattedAddress = c.getString(1);
                        structuredPostalList.add(structuredPostal);
                    }
                } finally {
                    if (c != null) c.close();
                }

                if (structuredPostalList.isEmpty()) {
                    // The selected contact has no addresses: create one now and edit it
                    a.createAddressAndEdit(contactId);
                } else if (structuredPostalList.size() == 1) {
                    // The selected contact has 1 address
                    StructuredPostal structuredPostal = structuredPostalList.get(0);
                    if (AddressInfo.isAugmented(structuredPostal.formattedAddress)) {
                        // The address is already augmented: create a new address now and edit it
                        a.createAddressAndEdit(contactId);
                    } else {
                        // The address is not augmented: edit it now
                        a.startAddressInfoEditActivity(structuredPostal.uri);
                    }
                } else {
                    // The selected contact has several addresses: ask the user which one they want to edit
                    a.chooseAddressToEdit(contactId, structuredPostalList);
                }
            }
        }).execute(getSupportFragmentManager());
    }

    private void startAddressInfoEditActivity(Uri uri) {
        Intent intent = new Intent(this, AddressInfoEditActivity.class);
        intent.setData(uri);
        this.startActivity(intent);
    }

    private void createAddressAndEdit(long contactId) {
        Log.d("contactId=" + contactId);

        // We need a raw contact for the selected contact.
        // If there are several, just arbitrarily pick the first one - this is not ideal, but the alternative would be to ask the user
        // which is not cool either.
        String[] projection = {ContactsContract.RawContacts._ID};
        String selection = ContactsContract.RawContacts.CONTACT_ID + "=?";
        String[] selectionArgs = {String.valueOf(contactId)};
        Cursor c = getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, projection, selection, selectionArgs, null);
        long rawContactId = -1;
        try {
            if (c.moveToFirst()) {
                rawContactId = c.getLong(0);
            } else {
                // Should never happen
                Log.e("Could not find raw contact for contact " + contactId, new Exception());
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(AddressInfoListActivity.this, R.string.common_unexpected, Toast.LENGTH_LONG).show();
                    }
                });
                return;
            }
        } finally {
            c.close();
        }

        ContentValues contentValues = new ContentValues(2);
        contentValues.put(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
        contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, "");
        contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
        Uri res = getContentResolver().insert(ContactsContract.Data.CONTENT_URI, contentValues);
        Log.d("res=" + res);
        startAddressInfoEditActivity(res);
    }

    private void chooseAddressToEdit(long contactId, ArrayList<StructuredPostal> structuredPostalList) {
        Log.d();
        ArrayList<CharSequence> items = new ArrayList<>(structuredPostalList.size());
        Bundle payload = new Bundle();
        payload.putLong("contactId", contactId);
        ArrayList<Parcelable> uris = new ArrayList<>(structuredPostalList.size());
        for (StructuredPostal structuredPostal : structuredPostalList) {
            if (AddressInfo.isAugmented(structuredPostal.formattedAddress)) {
                // Skip addresses that are already augmented
                continue;
            }
            items.add(structuredPostal.formattedAddress);
            uris.add(structuredPostal.uri);
        }

        if (uris.isEmpty()) {
            // After skipping augmented addresses, we may have none left.
            // In this case, create one now and edit it.
            createAddressAndEdit(contactId);
            return;
        } else if (uris.size() == 1) {
            // After skipping augmented addresses, we only have one left: edit it now
            startAddressInfoEditActivity((Uri) uris.get(0));
            return;
        }

        // Ask the user which address they want to edit
        AlertDialogFragment dialogFragment = AlertDialogFragment.newInstance(DIALOG_CHOOSE_ADDRESS_TO_EDIT);
        dialogFragment.setItems(items);
        payload.putParcelableArrayList("uris", uris);
        dialogFragment.setTitle(R.string.addressInfo_list_chooseAddress);
        dialogFragment.setPayload(payload);
        dialogFragment.show(getSupportFragmentManager());
    }


    /*
     * AlertDialogListener implementation.
     */
    //region

    @Override
    public void onClickPositive(int tag, Object payload) {
        switch (tag) {
            case DIALOG_LOCATION_SETTINGS: startActivity(Intent.createChooser(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), null)); break;
        }
    }

    @Override
    public void onClickNegative(int tag, Object payload) {}

    @Override
    public void onClickListItem(int tag, int index, Object payload) {
        switch (tag) {
            case DIALOG_CHOOSE_ADDRESS_TO_EDIT:
                Bundle payloadBundle = (Bundle) payload;
                ArrayList<Parcelable> uris = payloadBundle.getParcelableArrayList("uris");
                long contactId = payloadBundle.getLong("contactId");
                Uri chosenUri = (Uri) uris.get(index);
                Log.d("contactId=" + contactId + " chosenUri=" + chosenUri);
                startAddressInfoEditActivity(chosenUri);
                break;
        }
    }

    //endregion


    /*
     * AddressInfoCallbacks implementation.
     */
    //region

    @Override
    public void onAddressInfoClicked(AddressInfo addressInfo) {
        Log.d("addressInfo=" + addressInfo.uri);
        startAddressInfoEditActivity(addressInfo.uri);
    }

    @Override
    public void onListLoaded(boolean isEmpty) {
        // First disable any previously installed listener
        mSwiGeofencing.setOnCheckedChangeListener(null); if (isEmpty) {
            // Empty list, do not bother enabling the geofencing switch
            mSwiGeofencing.setEnabled(false); mSwiGeofencing.setChecked(false);
        } else {
            // Enable the switch
            mSwiGeofencing.setEnabled(true);
            // Check it if enabled in prefs
            SharedPreferences preferenceManager = PreferenceManager.getDefaultSharedPreferences(this);
            boolean enabled = preferenceManager.getBoolean(Constants.PREF_GEOFENCING_ENABLED, Constants.PREF_GEOFENCING_ENABLED_DEFAULT);
            mSwiGeofencing.setChecked(enabled);
            // Show disabled indicator if needed
            if (enabled) {
                mConGeofencingDisabled.setVisibility(View.GONE);
            } else {
                mConGeofencingDisabled.setVisibility(View.VISIBLE);
            }
        }
        // Install listener
        mSwiGeofencing.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                onGeofencingCheckedChanged(isChecked);
            }
        });
    }

    //endregion


    private void onGeofencingCheckedChanged(boolean isChecked) {
        SharedPreferences preferenceManager = PreferenceManager.getDefaultSharedPreferences(this);
        preferenceManager.edit().putBoolean(Constants.PREF_GEOFENCING_ENABLED, isChecked).commit();
        GeofencingService.refresh(this);
        if (isChecked) {
            Toast.makeText(this, R.string.addressInfo_list_geofencingOn, Toast.LENGTH_SHORT).show();
            mConGeofencingDisabled.animate().alpha(0f).setListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {}

                @Override
                public void onAnimationEnd(Animator animation) {
                    mConGeofencingDisabled.setVisibility(View.GONE);
                }

                @Override
                public void onAnimationCancel(Animator animation) {}

                @Override
                public void onAnimationRepeat(Animator animation) {}
            });
        } else {
            mConGeofencingDisabled.setAlpha(0f); mConGeofencingDisabled.setVisibility(View.VISIBLE); mConGeofencingDisabled.post(new Runnable() {
                @Override
                public void run() {
                    alignUpArrow(); mConGeofencingDisabled.animate().alpha(1f).setListener(null);
                }
            });
        }
    }

    private void alignUpArrow() {
        Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int displayWidth = size.x;

        Rect switchLocation = UiUtil.getLocationInWindow(mSwiGeofencing); Log.d("switchLocation=" + switchLocation);
        int diff = displayWidth - switchLocation.right; LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mImgArrowUp.getLayoutParams();
        layoutParams.rightMargin = diff + mSwiGeofencing.getWidth() / 2 - mImgArrowUp.getWidth() / 2; mImgArrowUp.setLayoutParams(layoutParams);
    }
}




Java Source Code List

org.jraf.android.dcn.common.wear.WearHelper.java
org.jraf.android.dcn.handheld.Constants.java
org.jraf.android.dcn.handheld.app.Application.java
org.jraf.android.dcn.handheld.app.addressinfo.edit.AddressInfoEditActivity.java
org.jraf.android.dcn.handheld.app.addressinfo.list.AddressInfoAdapter.java
org.jraf.android.dcn.handheld.app.addressinfo.list.AddressInfoCallbacks.java
org.jraf.android.dcn.handheld.app.addressinfo.list.AddressInfoListActivity.java
org.jraf.android.dcn.handheld.app.addressinfo.list.AddressInfoListFragment.java
org.jraf.android.dcn.handheld.app.addressinfo.list.AddressInfoLoader.java
org.jraf.android.dcn.handheld.app.boot.BootCompletedBroadcastReceiver.java
org.jraf.android.dcn.handheld.app.geofencing.GeofencingHelper.java
org.jraf.android.dcn.handheld.app.geofencing.GeofencingService.java
org.jraf.android.dcn.handheld.app.wear.NotificationWearableListenerService.java
org.jraf.android.dcn.handheld.model.addressinfo.AddressInfo.java
org.jraf.android.dcn.handheld.model.contactinfo.ContactInfo.java
org.jraf.android.dcn.handheld.util.picasso.RoundTransformation.java
org.jraf.android.dcn.handheld.util.picasso.location.LocationUtil.java
org.jraf.android.dcn.wearable.app.notif.NotificationIntentService.java
org.jraf.android.dcn.wearable.app.notif.NotificationWearableListenerService.java