Home | History | Annotate | Download | only in conversationsettings
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.messaging.ui.conversationsettings;
     17 
     18 import android.app.Activity;
     19 import android.app.AlertDialog;
     20 import android.app.Fragment;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.Intent;
     24 import android.content.res.Resources;
     25 import android.database.Cursor;
     26 import android.media.RingtoneManager;
     27 import android.os.Bundle;
     28 import android.os.Parcelable;
     29 import android.provider.Settings;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.ArrayAdapter;
     34 import android.widget.BaseAdapter;
     35 import android.widget.ListView;
     36 import android.widget.TextView;
     37 
     38 import com.android.messaging.R;
     39 import com.android.messaging.datamodel.DataModel;
     40 import com.android.messaging.datamodel.binding.Binding;
     41 import com.android.messaging.datamodel.binding.BindingBase;
     42 import com.android.messaging.datamodel.data.ParticipantData;
     43 import com.android.messaging.datamodel.data.ParticipantListItemData;
     44 import com.android.messaging.datamodel.data.PeopleAndOptionsData;
     45 import com.android.messaging.datamodel.data.PeopleAndOptionsData.PeopleAndOptionsDataListener;
     46 import com.android.messaging.datamodel.data.PeopleOptionsItemData;
     47 import com.android.messaging.datamodel.data.PersonItemData;
     48 import com.android.messaging.ui.CompositeAdapter;
     49 import com.android.messaging.ui.PersonItemView;
     50 import com.android.messaging.ui.UIIntents;
     51 import com.android.messaging.ui.conversation.ConversationActivity;
     52 import com.android.messaging.util.Assert;
     53 
     54 import java.util.ArrayList;
     55 import java.util.List;
     56 
     57 /**
     58  * Shows a list of participants of a conversation and displays options.
     59  */
     60 public class PeopleAndOptionsFragment extends Fragment
     61         implements PeopleAndOptionsDataListener, PeopleOptionsItemView.HostInterface {
     62     private ListView mListView;
     63     private OptionsListAdapter mOptionsListAdapter;
     64     private PeopleListAdapter mPeopleListAdapter;
     65     private final Binding<PeopleAndOptionsData> mBinding =
     66             BindingBase.createBinding(this);
     67 
     68     private static final int REQUEST_CODE_RINGTONE_PICKER = 1000;
     69 
     70     @Override
     71     public void onCreate(final Bundle savedInstanceState) {
     72         super.onCreate(savedInstanceState);
     73         mBinding.getData().init(getLoaderManager(), mBinding);
     74     }
     75 
     76     @Override
     77     public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
     78             final Bundle savedInstanceState) {
     79         final View view = inflater.inflate(R.layout.people_and_options_fragment, container, false);
     80         mListView = (ListView) view.findViewById(android.R.id.list);
     81         mPeopleListAdapter = new PeopleListAdapter(getActivity());
     82         mOptionsListAdapter = new OptionsListAdapter();
     83         final CompositeAdapter compositeAdapter = new CompositeAdapter(getActivity());
     84         compositeAdapter.addPartition(new PeopleAndOptionsPartition(mOptionsListAdapter,
     85                 R.string.general_settings_title, false));
     86         compositeAdapter.addPartition(new PeopleAndOptionsPartition(mPeopleListAdapter,
     87                 R.string.participant_list_title, true));
     88         mListView.setAdapter(compositeAdapter);
     89         return view;
     90     }
     91 
     92     @Override
     93     public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
     94         super.onActivityResult(requestCode, resultCode, data);
     95         if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_RINGTONE_PICKER) {
     96             final Parcelable pick = data.getParcelableExtra(
     97                     RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
     98             final String pickedUri = pick == null ? "" : pick.toString();
     99             mBinding.getData().setConversationNotificationSound(mBinding, pickedUri);
    100         }
    101     }
    102 
    103     @Override
    104     public void onDestroy() {
    105         super.onDestroy();
    106         mBinding.unbind();
    107     }
    108 
    109     public void setConversationId(final String conversationId) {
    110         Assert.isTrue(getView() == null);
    111         Assert.notNull(conversationId);
    112         mBinding.bind(DataModel.get().createPeopleAndOptionsData(conversationId, getActivity(),
    113                 this));
    114     }
    115 
    116     @Override
    117     public void onOptionsCursorUpdated(final PeopleAndOptionsData data, final Cursor cursor) {
    118         Assert.isTrue(cursor == null || cursor.getCount() == 1);
    119         mBinding.ensureBound(data);
    120         mOptionsListAdapter.swapCursor(cursor);
    121     }
    122 
    123     @Override
    124     public void onParticipantsListLoaded(final PeopleAndOptionsData data,
    125             final List<ParticipantData> participants) {
    126         mBinding.ensureBound(data);
    127         mPeopleListAdapter.updateParticipants(participants);
    128         final ParticipantData otherParticipant = participants.size() == 1 ?
    129                 participants.get(0) : null;
    130         mOptionsListAdapter.setOtherParticipant(otherParticipant);
    131     }
    132 
    133     @Override
    134     public void onOptionsItemViewClicked(final PeopleOptionsItemData item,
    135             final boolean isChecked) {
    136         switch (item.getItemId()) {
    137             case PeopleOptionsItemData.SETTING_NOTIFICATION_ENABLED:
    138                 mBinding.getData().enableConversationNotifications(mBinding, isChecked);
    139                 break;
    140 
    141             case PeopleOptionsItemData.SETTING_NOTIFICATION_SOUND_URI:
    142                 final Intent ringtonePickerIntent = UIIntents.get().getRingtonePickerIntent(
    143                         getString(R.string.notification_sound_pref_title),
    144                         item.getRingtoneUri(), Settings.System.DEFAULT_NOTIFICATION_URI,
    145                         RingtoneManager.TYPE_NOTIFICATION);
    146                 startActivityForResult(ringtonePickerIntent, REQUEST_CODE_RINGTONE_PICKER);
    147                 break;
    148 
    149             case PeopleOptionsItemData.SETTING_NOTIFICATION_VIBRATION:
    150                 mBinding.getData().enableConversationNotificationVibration(mBinding,
    151                         isChecked);
    152                 break;
    153 
    154             case PeopleOptionsItemData.SETTING_BLOCKED:
    155                 if (item.getOtherParticipant().isBlocked()) {
    156                     mBinding.getData().setDestinationBlocked(mBinding, false);
    157                     break;
    158                 }
    159                 final Resources res = getResources();
    160                 final Activity activity = getActivity();
    161                 new AlertDialog.Builder(activity)
    162                         .setTitle(res.getString(R.string.block_confirmation_title,
    163                                 item.getOtherParticipant().getDisplayDestination()))
    164                         .setMessage(res.getString(R.string.block_confirmation_message))
    165                         .setNegativeButton(android.R.string.cancel, null)
    166                         .setPositiveButton(android.R.string.ok,
    167                                 new DialogInterface.OnClickListener() {
    168                             @Override
    169                             public void onClick(DialogInterface arg0, int arg1) {
    170                                 mBinding.getData().setDestinationBlocked(mBinding, true);
    171                                 activity.setResult(ConversationActivity.FINISH_RESULT_CODE);
    172                                 activity.finish();
    173                             }
    174                         })
    175                         .create()
    176                         .show();
    177                 break;
    178         }
    179     }
    180 
    181     /**
    182      * A simple adapter that takes a conversation metadata cursor and binds
    183      * PeopleAndOptionsItemViews to individual COLUMNS of the first cursor record. (Note
    184      * that this is not a CursorAdapter because it treats individual columns of the cursor as
    185      * separate options to display for the conversation, e.g. notification settings).
    186      */
    187     private class OptionsListAdapter extends BaseAdapter {
    188         private Cursor mOptionsCursor;
    189         private ParticipantData mOtherParticipantData;
    190 
    191         public Cursor swapCursor(final Cursor newCursor) {
    192             final Cursor oldCursor = mOptionsCursor;
    193             if (newCursor != oldCursor) {
    194                 mOptionsCursor = newCursor;
    195                 notifyDataSetChanged();
    196             }
    197             return oldCursor;
    198         }
    199 
    200         public void setOtherParticipant(final ParticipantData participantData) {
    201             if (mOtherParticipantData != participantData) {
    202                 mOtherParticipantData = participantData;
    203                 notifyDataSetChanged();
    204             }
    205         }
    206 
    207         @Override
    208         public int getCount() {
    209             int count = PeopleOptionsItemData.SETTINGS_COUNT;
    210             if (mOtherParticipantData == null) {
    211                 count--;
    212             }
    213             return mOptionsCursor == null ? 0 : count;
    214         }
    215 
    216         @Override
    217         public Object getItem(final int position) {
    218             return null;
    219         }
    220 
    221         @Override
    222         public long getItemId(final int position) {
    223             return 0;
    224         }
    225 
    226         @Override
    227         public View getView(final int position, final View convertView, final ViewGroup parent) {
    228             final PeopleOptionsItemView itemView;
    229             if (convertView != null && convertView instanceof PeopleOptionsItemView) {
    230                 itemView = (PeopleOptionsItemView) convertView;
    231             } else {
    232                 final LayoutInflater inflater = (LayoutInflater) getActivity()
    233                         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    234                 itemView = (PeopleOptionsItemView)
    235                         inflater.inflate(R.layout.people_options_item_view, parent, false);
    236             }
    237             mOptionsCursor.moveToFirst();
    238             itemView.bind(mOptionsCursor, position, mOtherParticipantData,
    239                     PeopleAndOptionsFragment.this);
    240             return itemView;
    241         }
    242     }
    243 
    244     /**
    245      * An adapter that takes a list of ParticipantData and displays them as a list of
    246      * ParticipantListItemViews.
    247      */
    248     private class PeopleListAdapter extends ArrayAdapter<ParticipantData> {
    249         public PeopleListAdapter(final Context context) {
    250             super(context, R.layout.people_list_item_view, new ArrayList<ParticipantData>());
    251         }
    252 
    253         public void updateParticipants(final List<ParticipantData> newList) {
    254             clear();
    255             addAll(newList);
    256             notifyDataSetChanged();
    257         }
    258 
    259         @Override
    260         public View getView(final int position, final View convertView, final ViewGroup parent) {
    261             PersonItemView itemView;
    262             final ParticipantData item = getItem(position);
    263             if (convertView != null && convertView instanceof PersonItemView) {
    264                 itemView = (PersonItemView) convertView;
    265             } else {
    266                 final LayoutInflater inflater = (LayoutInflater) getContext()
    267                         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    268                 itemView = (PersonItemView) inflater.inflate(R.layout.people_list_item_view, parent,
    269                         false);
    270             }
    271             final ParticipantListItemData itemData =
    272                     DataModel.get().createParticipantListItemData(item);
    273             itemView.bind(itemData);
    274 
    275             // Any click on the row should have the same effect as clicking the avatar icon
    276             final PersonItemView itemViewClosure = itemView;
    277             itemView.setListener(new PersonItemView.PersonItemViewListener() {
    278                 @Override
    279                 public void onPersonClicked(final PersonItemData data) {
    280                     itemViewClosure.performClickOnAvatar();
    281                 }
    282 
    283                 @Override
    284                 public boolean onPersonLongClicked(final PersonItemData data) {
    285                     if (mBinding.isBound()) {
    286                         final CopyContactDetailDialog dialog = new CopyContactDetailDialog(
    287                                 getContext(), data.getDetails());
    288                         dialog.show();
    289                         return true;
    290                     }
    291                     return false;
    292                 }
    293             });
    294             return itemView;
    295         }
    296     }
    297 
    298     /**
    299      * Represents a partition/section in the People & Options list (e.g. "general options" and
    300      * "people in this conversation" sections).
    301      */
    302     private class PeopleAndOptionsPartition extends CompositeAdapter.Partition {
    303         private final int mHeaderResId;
    304         private final boolean mNeedDivider;
    305 
    306         public PeopleAndOptionsPartition(final BaseAdapter adapter, final int headerResId,
    307                 final boolean needDivider) {
    308             super(true /* showIfEmpty */, true /* hasHeader */, adapter);
    309             mHeaderResId = headerResId;
    310             mNeedDivider = needDivider;
    311         }
    312 
    313         @Override
    314         public View getHeaderView(final View convertView, final ViewGroup parentView) {
    315             View view = null;
    316             if (convertView != null && convertView.getId() == R.id.people_and_options_header) {
    317                 view = convertView;
    318             } else {
    319                 view = LayoutInflater.from(getActivity()).inflate(
    320                         R.layout.people_and_options_section_header, parentView, false);
    321             }
    322             final TextView text = (TextView) view.findViewById(R.id.header_text);
    323             final View divider = view.findViewById(R.id.divider);
    324             text.setText(mHeaderResId);
    325             divider.setVisibility(mNeedDivider ? View.VISIBLE : View.GONE);
    326             return view;
    327         }
    328     }
    329 }
    330