1/* 2 * Copyright (C) 2011 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 17package com.android.contacts.detail; 18 19import com.android.contacts.ContactLoader; 20import com.android.contacts.R; 21import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener; 22import com.android.contacts.detail.ContactDetailDisplayUtils.StreamPhotoTag; 23import com.android.contacts.model.AccountType; 24import com.android.contacts.model.AccountTypeManager; 25import com.android.contacts.util.StreamItemEntry; 26 27import android.app.ListFragment; 28import android.content.ContentUris; 29import android.content.Intent; 30import android.net.Uri; 31import android.os.Bundle; 32import android.provider.ContactsContract.StreamItems; 33import android.view.LayoutInflater; 34import android.view.View; 35import android.view.View.OnClickListener; 36import android.view.ViewGroup; 37import android.widget.AbsListView.OnScrollListener; 38import android.widget.ListView; 39 40public class ContactDetailUpdatesFragment extends ListFragment 41 implements FragmentKeyListener, ViewOverlay { 42 43 private static final String TAG = "ContactDetailUpdatesFragment"; 44 45 private ContactLoader.Result mContactData; 46 private Uri mLookupUri; 47 48 private LayoutInflater mInflater; 49 private StreamItemAdapter mStreamItemAdapter; 50 51 private float mInitialAlphaValue; 52 53 /** 54 * This optional view adds an alpha layer over the entire fragment. 55 */ 56 private View mAlphaLayer; 57 58 /** 59 * This optional view adds a layer over the entire fragment so that when visible, it intercepts 60 * all touch events on the fragment. 61 */ 62 private View mTouchInterceptLayer; 63 64 private OnScrollListener mVerticalScrollListener; 65 66 /** 67 * Listener on clicks on a stream item. 68 * <p> 69 * It assumes the view has a tag of type {@link StreamItemEntry} associated with it. 70 */ 71 private final View.OnClickListener mStreamItemClickListener = new View.OnClickListener() { 72 @Override 73 public void onClick(View view) { 74 StreamItemEntry streamItemEntry = (StreamItemEntry) view.getTag(); 75 if (streamItemEntry == null) { 76 // Ignore if this item does not have a stream item associated with it. 77 return; 78 } 79 final AccountType accountType = getAccountTypeForStreamItemEntry(streamItemEntry); 80 81 final Uri uri = ContentUris.withAppendedId(StreamItems.CONTENT_URI, 82 streamItemEntry.getId()); 83 final Intent intent = new Intent(Intent.ACTION_VIEW, uri); 84 intent.setClassName(accountType.resPackageName, 85 accountType.getViewStreamItemActivity()); 86 startActivity(intent); 87 } 88 }; 89 90 private final View.OnClickListener mStreamItemPhotoItemClickListener 91 = new View.OnClickListener() { 92 @Override 93 public void onClick(View view) { 94 StreamPhotoTag tag = (StreamPhotoTag) view.getTag(); 95 if (tag == null) { 96 return; 97 } 98 final AccountType accountType = getAccountTypeForStreamItemEntry(tag.streamItem); 99 100 final Intent intent = new Intent(Intent.ACTION_VIEW, tag.getStreamItemPhotoUri()); 101 intent.setClassName(accountType.resPackageName, 102 accountType.getViewStreamItemPhotoActivity()); 103 startActivity(intent); 104 } 105 }; 106 107 private AccountType getAccountTypeForStreamItemEntry(StreamItemEntry streamItemEntry) { 108 return AccountTypeManager.getInstance(getActivity()).getAccountType( 109 streamItemEntry.getAccountType(), streamItemEntry.getDataSet()); 110 } 111 112 public ContactDetailUpdatesFragment() { 113 // Explicit constructor for inflation 114 } 115 116 @Override 117 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { 118 mInflater = inflater; 119 View rootView = mInflater.inflate(R.layout.contact_detail_updates_fragment, container, 120 false); 121 122 mTouchInterceptLayer = rootView.findViewById(R.id.touch_intercept_overlay); 123 mAlphaLayer = rootView.findViewById(R.id.alpha_overlay); 124 ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, mInitialAlphaValue); 125 126 return rootView; 127 } 128 129 @Override 130 public void onViewCreated(View view, Bundle savedInstanceState) { 131 super.onViewCreated(view, savedInstanceState); 132 mStreamItemAdapter = new StreamItemAdapter(getActivity(), mStreamItemClickListener, 133 mStreamItemPhotoItemClickListener); 134 setListAdapter(mStreamItemAdapter); 135 getListView().setOnScrollListener(mVerticalScrollListener); 136 137 // It is possible that the contact data was set to the fragment when it was first attached 138 // to the activity, but before this method was called because the fragment was not 139 // visible on screen yet (i.e. using a {@link ViewPager}), so display the data if we already 140 // have it. 141 if (mContactData != null) { 142 mStreamItemAdapter.setStreamItems(mContactData.getStreamItems()); 143 } 144 } 145 146 public void setData(Uri lookupUri, ContactLoader.Result result) { 147 if (result == null) { 148 return; 149 } 150 mLookupUri = lookupUri; 151 mContactData = result; 152 153 // If the adapter has been created already, then try to set stream items. Otherwise, 154 // wait for the adapter to get initialized, after which we will try to set the stream items 155 // again. 156 if (mStreamItemAdapter != null) { 157 mStreamItemAdapter.setStreamItems(mContactData.getStreamItems()); 158 } 159 } 160 161 /** 162 * Reset the list adapter in this {@link Fragment} to get rid of any saved scroll position 163 * from a previous contact. 164 */ 165 public void resetAdapter() { 166 setListAdapter(mStreamItemAdapter); 167 } 168 169 @Override 170 public void setAlphaLayerValue(float alpha) { 171 // If the alpha layer is not ready yet, store it for later when the view is initialized 172 if (mAlphaLayer == null) { 173 mInitialAlphaValue = alpha; 174 } else { 175 // Otherwise set the value immediately 176 ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, alpha); 177 } 178 } 179 180 @Override 181 public void enableTouchInterceptor(OnClickListener clickListener) { 182 if (mTouchInterceptLayer != null) { 183 mTouchInterceptLayer.setVisibility(View.VISIBLE); 184 mTouchInterceptLayer.setOnClickListener(clickListener); 185 } 186 } 187 188 @Override 189 public void disableTouchInterceptor() { 190 if (mTouchInterceptLayer != null) { 191 mTouchInterceptLayer.setVisibility(View.GONE); 192 } 193 } 194 195 @Override 196 public boolean handleKeyDown(int keyCode) { 197 return false; 198 } 199 200 public void setVerticalScrollListener(OnScrollListener listener) { 201 mVerticalScrollListener = listener; 202 } 203 204 /** 205 * Returns the top coordinate of the first item in the {@link ListView}. If the first item 206 * in the {@link ListView} is not visible or there are no children in the list, then return 207 * Integer.MIN_VALUE. Note that the returned value will be <= 0 because the first item in the 208 * list cannot have a positive offset. 209 */ 210 public int getFirstListItemOffset() { 211 return ContactDetailDisplayUtils.getFirstListItemOffset(getListView()); 212 } 213 214 /** 215 * Tries to scroll the first item to the given offset (this can be a no-op if the list is 216 * already in the correct position). 217 * @param offset which should be <= 0 218 */ 219 public void requestToMoveToOffset(int offset) { 220 ContactDetailDisplayUtils.requestToMoveToOffset(getListView(), offset); 221 } 222} 223