mobisocial.musubi.ui.FeedDetailsActivity.java Source code

Java tutorial

Introduction

Here is the source code for mobisocial.musubi.ui.FeedDetailsActivity.java

Source

/*
 * Copyright 2012 The Stanford MobiSocial Laboratory
 *
 * 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 mobisocial.musubi.ui;

import java.io.File;
import java.io.IOException;
import java.util.regex.Pattern;

import mobisocial.metrics.MusubiMetrics;
import mobisocial.musubi.App;
import mobisocial.musubi.Helpers;
import mobisocial.musubi.MembersActivity.FeedMembersFragment.FeedMembersCursorLoader;
import mobisocial.musubi.R;
import mobisocial.musubi.model.MFeed;
import mobisocial.musubi.model.MIdentity;
import mobisocial.musubi.model.helpers.DatabaseManager;
import mobisocial.musubi.model.helpers.FeedManager;
import mobisocial.musubi.model.helpers.IdentitiesManager;
import mobisocial.musubi.model.helpers.MyAccountManager;
import mobisocial.musubi.nearby.GpsBroadcastTask;
import mobisocial.musubi.objects.FeedNameObj;
import mobisocial.musubi.objects.IntroductionObj;
import mobisocial.musubi.ui.util.EmojiSpannableFactory;
import mobisocial.musubi.ui.util.UiUtil;
import mobisocial.musubi.ui.widget.ActionBarLite;
import mobisocial.musubi.ui.widget.MultiIdentitySelector;
import mobisocial.musubi.ui.widget.MultiIdentitySelector.OnRequestAddIdentityListener;
import mobisocial.musubi.util.CommonLayouts;
import mobisocial.musubi.util.InstrumentedActivity;
import mobisocial.musubi.util.PhotoTaker;
import mobisocial.musubi.util.UriImage;
import mobisocial.socialkit.Obj;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.database.Cursor;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Intents.Insert;
import android.provider.MediaStore;
import android.provider.Settings;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.SupportActivity;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.Spannable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class FeedDetailsActivity extends MusubiBaseActivity
        implements OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor> {
    DatabaseManager mDb;

    private static final int sDeletedColor = Color.parseColor("#66FF3333");
    boolean mDetailsChanged = false;
    byte[] mThumbnailBytes;
    ImageView mThumbnailView;
    EditText mNameEditText;
    EditText mBroadcastPassword;
    ListView mFeedMembersView;
    Context mContext;

    IdentitiesManager mIdentitiesManager;
    ContactListCursorAdapter mContacts;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        setContentView(R.layout.feed_details);
        setTitle("Feed Details");
        mDb = new DatabaseManager(this);

        SQLiteOpenHelper helper = App.getDatabaseSource(this);
        mIdentitiesManager = new IdentitiesManager(helper);
        mContacts = new ContactListCursorAdapter(this, null);

        mFeedMembersView = (ListView) findViewById(R.id.feed_details_members_list);
        LayoutInflater inflater = getLayoutInflater();
        ViewGroup header = (ViewGroup) inflater.inflate(R.layout.feed_details_header, mFeedMembersView, false);
        mFeedMembersView.addHeaderView(header, null, false);
        mFeedMembersView.setTextFilterEnabled(true);
        mFeedMembersView.setFastScrollEnabled(true);
        mFeedMembersView.setOnItemClickListener(this);
        mFeedMembersView.setCacheColorHint(Color.WHITE);
        mFeedMembersView.setAdapter(mContacts);

        mNameEditText = (EditText) header.findViewById(R.id.feed_title_edittext);
        mBroadcastPassword = (EditText) header.findViewById(R.id.broadcast_password);
        mThumbnailView = (ImageView) header.findViewById(R.id.icon);

        String name = null;
        if (savedInstanceState != null) {
            name = savedInstanceState.getString("name");
            mThumbnailBytes = savedInstanceState.getByteArray("thumbnailBytes");
            mDetailsChanged = savedInstanceState.getBoolean("detailsChanged");
        } else {
            Long feedId = Long.parseLong(getIntent().getData().getLastPathSegment());
            MFeed feed = mDb.getFeedManager().lookupFeed(feedId);
            name = UiUtil.getFeedNameFromMembersList(mDb.getFeedManager(), feed);
            mThumbnailBytes = mDb.getFeedManager().getFeedThumbnailForId(feedId);
        }
        Spannable span = EmojiSpannableFactory.getInstance(this).newSpannable(name);
        mNameEditText.setText(span);
        mNameEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                mDetailsChanged = true;
                refreshUI();
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                EmojiSpannableFactory.getInstance(mContext).updateSpannable(s);
            }
        });

        getSupportLoaderManager().initLoader(0, null, this);
        refreshUI();
    }

    public void onClickAddMembers(View v) {
        ((InstrumentedActivity) this).showDialog(AddPeopleDialog.newInstance(getIntent().getData()));
    }

    public void onClickIcon(View v) {
        SelectImageDialogFragment sidf = SelectImageDialogFragment.newInstance();
        showDialog(sidf);
    }

    public void onClickBroadcast(View v) {
        long id = Long.parseLong(getIntent().getData().getLastPathSegment());
        FeedManager fm = new FeedManager(App.getDatabaseSource(this));
        final MFeed f = fm.lookupFeed(id);

        String provider = Settings.Secure.getString(this.getContentResolver(),
                Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
        if (provider == null || !provider.contains("gps") || !provider.contains("network")) {
            new AlertDialog.Builder(this).setTitle("Location Settings").setMessage(
                    "You should enable both network-based and GPS-based location services to ensure your friends can find your groups.")
                    .setNegativeButton("Share Anyway", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            new GpsBroadcastTask(mContext, f, mBroadcastPassword.getText().toString()).execute();
                        }
                    }).setPositiveButton("Fix Settings First", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            try {
                                Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                startActivity(myIntent);
                            } catch (Throwable t) {
                                Log.e(TAG, "failed to launch location settings", t);
                            }
                        }
                    }).show();
        } else {
            new GpsBroadcastTask(mContext, f, mBroadcastPassword.getText().toString()).execute();
        }
    }

    @Override
    public void onBackPressed() {
        onClickSave(null);
    }

    public void onClickSave(View v) {
        if (mDetailsChanged) {
            String name = mNameEditText.getText().toString();
            Obj obj = FeedNameObj.from(name, mThumbnailBytes);
            Helpers.sendToFeed(this, obj, getIntent().getData());
        }
        finish();
    }

    public void onClickCancel(View v) {
        finish();
    }

    public void refreshUI() {
        if (mDetailsChanged) {
            findViewById(R.id.submit).setVisibility(View.VISIBLE);
            findViewById(R.id.cancel).setVisibility(View.VISIBLE);
        } else {
            findViewById(R.id.submit).setVisibility(View.GONE);
            findViewById(R.id.cancel).setVisibility(View.GONE);
        }

        if (mThumbnailBytes != null) {
            Bitmap bitmap = BitmapFactory.decodeByteArray(mThumbnailBytes, 0, mThumbnailBytes.length);
            mThumbnailView.setImageBitmap(bitmap);
        } else {
            mThumbnailView.setImageResource(R.drawable.group_icon);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putString("name", mNameEditText.getText().toString());
        outState.putByteArray("thumbnailBytes", mThumbnailBytes);
        outState.putBoolean("detailsChanged", mDetailsChanged);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != RESULT_OK) {
            return;
        }
        if (SelectImageDialogFragment.isImageRequest(requestCode)) {
            new SelectImageDialogFragment.ThumbnailAsyncTask(this, requestCode, data) {
                protected void onPreExecute() {

                };

                @Override
                protected void onThumbnailResult(byte[] imageBytes) {
                    if (imageBytes != null) {
                        mThumbnailBytes = imageBytes;
                        mDetailsChanged = true;
                        refreshUI();
                    } else {
                        toast("Failed to load image");
                    }
                };
            }.execute();
        }
    }

    public static class SelectImageDialogFragment extends DialogFragment
            implements DialogInterface.OnClickListener {
        public static final int REQUEST_CAMERA_IMAGE = 58;
        public static final int REQUEST_GALLERY_IMAGE = 59;

        static final int SOURCE_CAMERA = 0;
        static final int SOURCE_GALLERY = 1;

        public static SelectImageDialogFragment newInstance() {
            Bundle args = new Bundle();
            SelectImageDialogFragment sidf = new SelectImageDialogFragment();
            sidf.setArguments(args);
            return sidf;
        }

        public static boolean isImageRequest(int requestCode) {
            return (requestCode == REQUEST_CAMERA_IMAGE || requestCode == REQUEST_GALLERY_IMAGE);
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            String[] sources = new String[] { "From Camera", "From Gallery" };
            return new AlertDialog.Builder(getActivity()).setTitle("Choose an image...").setItems(sources, this)
                    .create();
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            switch (which) {
            case SOURCE_CAMERA:
                final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(PhotoTaker.getTempFile(getActivity())));
                getActivity().startActivityForResult(intent, REQUEST_CAMERA_IMAGE);
                break;
            case SOURCE_GALLERY:
                Intent gallery = new Intent(Intent.ACTION_GET_CONTENT);
                gallery.setType("image/*");
                getActivity().startActivityForResult(gallery, REQUEST_GALLERY_IMAGE);
                break;
            }
        }

        public static abstract class ThumbnailAsyncTask extends AsyncTask<Void, Void, byte[]> {
            final Context mContext;
            final int mRequestCode;
            final Intent mData;

            public ThumbnailAsyncTask(Context context, int requestCode, Intent data) {
                mContext = context;
                mRequestCode = requestCode;
                mData = data;
            }

            @Override
            protected byte[] doInBackground(Void... params) {
                Uri imageUri;
                switch (mRequestCode) {
                case REQUEST_CAMERA_IMAGE:
                    File imageFile = PhotoTaker.getTempFile(mContext);
                    imageUri = Uri.fromFile(imageFile);
                    break;
                case REQUEST_GALLERY_IMAGE:
                    if (mData != null) {
                        imageUri = mData.getData();
                    } else {
                        imageUri = null;
                    }
                    break;
                default:
                    imageUri = null;
                }
                if (imageUri != null) {
                    UriImage uriImage = new UriImage(mContext, imageUri);
                    try {
                        return uriImage.getResizedImageData(300, 300, 20 * 1024, true);
                    } catch (IOException e) {
                        Log.e(TAG, "Error decoding image", e);
                        return null;
                    }
                } else {
                    Log.e(TAG, "bad request code");
                    return null;
                }
            }

            @Override
            protected final void onPostExecute(byte[] result) {
                onThumbnailResult(result);
            }

            protected abstract void onThumbnailResult(byte[] imageBytes);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        refreshUI();
    }

    @Override
    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
        long feedId = Long.parseLong(getIntent().getData().getLastPathSegment());
        return new FeedMembersCursorLoader(this, feedId);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mContacts.changeCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> arg0) {

    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Cursor cursor = (Cursor) mContacts.getItem(position - 1);
        long identityId = cursor.getLong(cursor.getColumnIndexOrThrow(MIdentity.COL_ID));
        Intent intent = new Intent(this, ViewProfileActivity.class);
        intent.putExtra(ViewProfileActivity.PROFILE_ID, identityId);
        this.startActivity(intent);
    }

    private class ContactListCursorAdapter extends CursorAdapter {
        public ContactListCursorAdapter(Context context, Cursor c) {
            super(context, c);
        }

        @Override
        public View newView(Context context, Cursor c, ViewGroup parent) {
            final LayoutInflater inflater = LayoutInflater.from(context);
            View v = inflater.inflate(R.layout.contacts_item, parent, false);
            bindView(v, context, c);
            return v;
        }

        @Override
        public void bindView(View v, Context context, Cursor cursor) {
            TextView unreadCount = (TextView) v.findViewById(R.id.unread_count);
            unreadCount.setVisibility(View.GONE);
            TextView nameText = (TextView) v.findViewById(R.id.name_text);
            TextView statusText = (TextView) v.findViewById(R.id.status_text);
            TextView principalText = (TextView) v.findViewById(R.id.principal_text);
            final ImageView icon = (ImageView) v.findViewById(R.id.icon);
            final ImageView presenceIcon = (ImageView) v.findViewById(R.id.presence_icon);
            presenceIcon.setVisibility(View.GONE);
            final ImageView nearbyIcon = (ImageView) v.findViewById(R.id.nearby_icon);
            nearbyIcon.setVisibility(View.GONE);
            final ImageView more = (ImageView) v.findViewById(R.id.more);

            long identityId = cursor.getLong(0);
            final MIdentity member = mIdentitiesManager.getIdentityForId(identityId);
            if (member == null) {
                unreadCount.setVisibility(View.INVISIBLE);
                nameText.setText("Missing contact data...");
                statusText.setText("");
                icon.setImageResource(R.drawable.ic_contact_picture);
                return;
            }

            nameText.setText(UiUtil.safeNameForIdentity(member));
            principalText.setText(UiUtil.safePrincipalForIdentity(member));
            icon.setImageBitmap(UiUtil.safeGetContactThumbnail(context, mIdentitiesManager, member));

            //nearbyIcon.setVisibility(c.nearby ? View.VISIBLE : View.GONE);
            more.setVisibility(View.GONE);

            ImageView musubiEnabled = (ImageView) v.findViewById(R.id.musubi_enabled);
            ImageView ignoredOverlay = (ImageView) v.findViewById(R.id.ignored_overlay);
            if (member.claimed_) {
                ignoredOverlay.setVisibility(View.GONE);
                nameText.setTextColor(Color.BLACK);
                principalText.setTextColor(Color.BLACK);
                musubiEnabled.setBackgroundResource(R.drawable.musubi_enabled);
            } else {
                ignoredOverlay.setVisibility(View.GONE);
                nameText.setTextColor(Color.BLACK);
                principalText.setTextColor(Color.BLACK);
                musubiEnabled.setBackgroundResource(R.drawable.musubi_disabled);
            }
            if (member.blocked_) {
                nameText.setTextColor(sDeletedColor);
                principalText.setTextColor(sDeletedColor);
                ignoredOverlay.setVisibility(View.VISIBLE);
            }
        }
    }

    public static class AddPeopleDialog extends DialogFragment {
        private static final int REQUEST_ADD_CONTACT = 0;
        MultiIdentitySelector mmIdentitySelector;
        Activity mActivity;

        public static AddPeopleDialog newInstance(Uri feedUri) {
            AddPeopleDialog f = new AddPeopleDialog();
            Bundle args = new Bundle();
            args.putParcelable("feedUri", feedUri);
            f.setArguments(args);
            return f;
        }

        @Override
        public void onAttach(SupportActivity activity) {
            super.onAttach(activity);
            mActivity = activity.asActivity();
            mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
        }

        @Override
        public void onDetach() {
            super.onDetach();
            mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setStyle(STYLE_NO_TITLE, R.style.Theme_D1tranlucent);
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == REQUEST_ADD_CONTACT) {
                if (resultCode == Activity.RESULT_OK) {
                    UiUtil.addedContact(mActivity, data, mmIdentitySelector);
                }
            }
        }

        private OnRequestAddIdentityListener mOnRequestAddIdentityListener = new OnRequestAddIdentityListener() {
            @Override
            public void onRequestAddIdentity(String enteredText) {
                Intent i = new Intent(Intent.ACTION_INSERT_OR_EDIT);
                i.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
                if (enteredText != null) {
                    Pattern emailPattern = Pattern.compile("\\b[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
                            Pattern.CASE_INSENSITIVE);
                    if (emailPattern.matcher(enteredText).matches()) {
                        i.putExtra(Insert.EMAIL, enteredText);
                    } else {
                        i.putExtra(Insert.NAME, enteredText);
                    }
                }
                startActivityForResult(i, REQUEST_ADD_CONTACT);
            }
        };

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            // Framework builds dialog with view defined in onCreateView.
            Dialog dialog = super.onCreateDialog(savedInstanceState);
            dialog.getWindow().getAttributes().windowAnimations = R.style.Animation_SlideFromTopHalfHeight;
            dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
            return dialog;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            Context context = getActivity();

            LinearLayout v = new LinearLayout(context);
            v.setMinimumWidth(500);
            v.setLayoutParams(CommonLayouts.FULL_WIDTH);
            v.setOrientation(LinearLayout.VERTICAL);
            v.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    dismiss();
                }
            });

            RelativeLayout.LayoutParams params;
            /////////////
            // Action bar
            /////////////
            ActionBarLite actionBar = new ActionBarLite(context);
            actionBar.setId(R.id.name);
            actionBar.setTitle("Add People");
            v.addView(actionBar);

            ////
            // Custom action bar area
            ////
            RelativeLayout contentFrame = new RelativeLayout(context);
            contentFrame.setLayoutParams(CommonLayouts.FULL_WIDTH);
            contentFrame.setBackgroundDrawable(actionBar.getBackground());

            // "Add" button
            Button b = new Button(context);
            b.setText(R.string.add);
            b.setOnClickListener(mmGoListener);
            params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
                    RelativeLayout.LayoutParams.WRAP_CONTENT);
            params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            params.addRule(RelativeLayout.BELOW, R.id.name);
            b.setLayoutParams(params);
            b.setId(R.id.add_contact);
            contentFrame.addView(b);

            // Multi-select textbox
            mmIdentitySelector = new MultiIdentitySelector(context);
            params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
                    RelativeLayout.LayoutParams.WRAP_CONTENT);
            params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
            params.addRule(RelativeLayout.LEFT_OF, R.id.add_contact);
            params.addRule(RelativeLayout.BELOW, R.id.name);
            mmIdentitySelector.setLayoutParams(params);
            mmIdentitySelector.setId(R.id.people);
            contentFrame.addView(mmIdentitySelector);
            mmIdentitySelector.setOnRequestAddIdentityListener(mOnRequestAddIdentityListener);

            int sz = 40;
            sz = (int) (sz * getResources().getDisplayMetrics().density / 160);

            actionBar.getCustomBar().addView(contentFrame);
            return v;
        }

        //TODO: this code makes pretty poor use for local vars/member vars to making it clear
        //and not wasteful
        final View.OnClickListener mmGoListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mmIdentitySelector.getSelectedIdentities().size() == 0) {
                    dismiss();
                    return;
                }

                Uri feedUri = getArguments().getParcelable("feedUri");
                long feedId = Long.parseLong(feedUri.getLastPathSegment());
                FeedManager fm = new FeedManager(App.getDatabaseSource(mActivity));
                for (MIdentity id : mmIdentitySelector.getSelectedIdentities()) {
                    fm.ensureFeedMember(feedId, id.id_);
                }
                UiUtil.addToWhitelistsIfNecessary(fm, new MyAccountManager(App.getDatabaseSource(mActivity)),
                        fm.getFeedMembers(fm.lookupFeed(feedId)), true);

                // Send an invisble feed object to force the feed to detect new members
                // and recognize their names and email addresses.
                Obj invitedObj = IntroductionObj.from(mmIdentitySelector.getSelectedIdentities(), true);
                Helpers.sendToFeed(mActivity, invitedObj, feedUri);

                App.getUsageMetrics(mActivity).report(MusubiMetrics.ADDED_PERSON_TO_FEED,
                        "" + mmIdentitySelector.getSelectedIdentities().size());
                dismiss();
            }
        };
    }
}