1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/* 2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project 3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License"); 5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License. 6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at 7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * http://www.apache.org/licenses/LICENSE-2.0 9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software 11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS, 12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and 14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License. 15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.ui; 17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.Fragment; 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ActivityNotFoundException; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Intent; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Bundle; 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.LayoutInflater; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.Menu; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.MenuInflater; 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.MenuItem; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.View; 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.View.OnLayoutChangeListener; 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.ViewGroup; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.ExpandableListAdapter; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.ExpandableListView; 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.ExpandableListView.OnChildClickListener; 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R; 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DataModel; 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.MediaScratchFileProvider; 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.binding.Binding; 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.binding.BindingBase; 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.PersonItemData; 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.VCardContactItemData; 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.PersonItemData.PersonItemDataListener; 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert; 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.SafeAsyncTask; 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.UiUtils; 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.UriUtil; 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/** 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * A fragment that shows the content of a VCard that contains one or more contacts. 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class VCardDetailFragment extends Fragment implements PersonItemDataListener { 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private final Binding<VCardContactItemData> mBinding = 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd BindingBase.createBinding(this); 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private ExpandableListView mListView; 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private VCardDetailAdapter mAdapter; 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private Uri mVCardUri; 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * We need to persist the VCard in the scratch directory before letting the user view it. 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * We save this Uri locally, so that if the user cancels the action and re-perform the add 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * to contacts action we don't have to persist it again. 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private Uri mScratchSpaceUri; 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onCreate(final Bundle savedInstanceState) { 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super.onCreate(savedInstanceState); 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd setHasOptionsMenu(true); 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public View onCreateView(final LayoutInflater inflater, final ViewGroup container, 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Bundle savedInstanceState) { 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.notNull(mVCardUri); 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final View view = inflater.inflate(R.layout.vcard_detail_fragment, container, false); 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView = (ExpandableListView) view.findViewById(R.id.list); 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView.addOnLayoutChangeListener(new OnLayoutChangeListener() { 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onLayoutChange(final View v, final int left, final int top, final int right, 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int bottom, final int oldLeft, final int oldTop, final int oldRight, 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int oldBottom) { 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView.setIndicatorBounds(mListView.getWidth() - getResources() 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd .getDimensionPixelSize(R.dimen.vcard_detail_group_indicator_width), 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView.getWidth()); 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }); 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView.setOnChildClickListener(new OnChildClickListener() { 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public boolean onChildClick(ExpandableListView expandableListView, View clickedView, 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd int groupPosition, int childPosition, long childId) { 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!(clickedView instanceof PersonItemView)) { 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return false; 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Intent intent = ((PersonItemView) clickedView).getClickIntent(); 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (intent != null) { 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd startActivity(intent); 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (ActivityNotFoundException e) { 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return false; 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return true; 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return false; 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }); 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mBinding.bind(DataModel.get().createVCardContactItemData(getActivity(), mVCardUri)); 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mBinding.getData().setListener(this); 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return view; 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onDestroy() { 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super.onDestroy(); 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mBinding.isBound()) { 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mBinding.unbind(); 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView.setAdapter((ExpandableListAdapter) null); 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private boolean shouldShowAddToContactsItem() { 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return mBinding.isBound() && mBinding.getData().hasValidVCard(); 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super.onCreateOptionsMenu(menu, inflater); 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inflater.inflate(R.menu.vcard_detail_fragment_menu, menu); 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final MenuItem addToContactsItem = menu.findItem(R.id.action_add_contact); 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd addToContactsItem.setVisible(shouldShowAddToContactsItem()); 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public boolean onOptionsItemSelected(final MenuItem item) { 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd switch (item.getItemId()) { 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd case R.id.action_add_contact: 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mBinding.ensureBound(); 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Uri vCardUri = mBinding.getData().getVCardUri(); 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // We have to do things in the background in case we need to copy the vcard data. 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd new SafeAsyncTask<Void, Void, Uri>() { 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected Uri doInBackgroundTimed(final Void... params) { 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // We can't delete the persisted vCard file because we don't know when to 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // delete it, since the app that uses it (contacts, dialer) may start or 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // shut down at any point. Therefore, we rely on the system to clean up 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // the cache directory for us. 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return mScratchSpaceUri != null ? mScratchSpaceUri : 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UriUtil.persistContentToScratchSpace(vCardUri); 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected void onPostExecute(final Uri result) { 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (result != null) { 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mScratchSpaceUri = result; 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (getActivity() != null) { 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd MediaScratchFileProvider.addUriToDisplayNameEntry( 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd result, mBinding.getData().getDisplayName()); 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UIIntents.get().launchSaveVCardToContactsActivity(getActivity(), 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd result); 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }.executeOnThreadPool(); 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return true; 164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd default: 166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return super.onOptionsItemSelected(item); 167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void setVCardUri(final Uri vCardUri) { 171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.isTrue(!mBinding.isBound()); 172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mVCardUri = vCardUri; 173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onPersonDataUpdated(final PersonItemData data) { 177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.isTrue(data instanceof VCardContactItemData); 178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mBinding.ensureBound(); 179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final VCardContactItemData vCardData = (VCardContactItemData) data; 180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Assert.isTrue(vCardData.hasValidVCard()); 181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mAdapter = new VCardDetailAdapter(getActivity(), vCardData.getVCardResource().getVCards()); 182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView.setAdapter(mAdapter); 183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Expand the contact card if there's only one contact. 185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (mAdapter.getGroupCount() == 1) { 186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mListView.expandGroup(0); 187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd getActivity().invalidateOptionsMenu(); 189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public void onPersonDataFailed(final PersonItemData data, final Exception exception) { 193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mBinding.ensureBound(); 194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd UiUtils.showToastAtBottom(R.string.failed_loading_vcard); 195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd getActivity().finish(); 196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 198