1/*
2 * Copyright (C) 2013 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 */
16package com.android.dialer.list;
17
18import android.app.Activity;
19import android.content.Intent;
20import android.content.res.Resources;
21import android.os.Bundle;
22import android.text.TextUtils;
23import android.view.View;
24import android.view.animation.Interpolator;
25import android.widget.AbsListView;
26import android.widget.AbsListView.OnScrollListener;
27import android.widget.ListView;
28
29import com.android.contacts.common.list.ContactEntryListAdapter;
30import com.android.contacts.common.list.ContactListItemView;
31import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
32import com.android.contacts.common.list.PhoneNumberPickerFragment;
33import com.android.contacts.common.util.ViewUtil;
34import com.android.dialer.DialtactsActivity;
35import com.android.dialer.R;
36import com.android.dialer.util.DialerUtils;
37import com.android.phone.common.animation.AnimUtils;
38
39public class SearchFragment extends PhoneNumberPickerFragment {
40
41    private OnListFragmentScrolledListener mActivityScrollListener;
42
43    /*
44     * Stores the untouched user-entered string that is used to populate the add to contacts
45     * intent.
46     */
47    private String mAddToContactNumber;
48    private int mActionBarHeight;
49    private int mShadowHeight;
50    private int mPaddingTop;
51    private int mShowDialpadDuration;
52    private int mHideDialpadDuration;
53
54    private HostInterface mActivity;
55
56    public interface HostInterface {
57        public boolean isActionBarShowing();
58        public boolean isDialpadShown();
59        public int getActionBarHideOffset();
60        public int getActionBarHeight();
61    }
62
63    @Override
64    public void onAttach(Activity activity) {
65        super.onAttach(activity);
66
67        setQuickContactEnabled(true);
68        setAdjustSelectionBoundsEnabled(false);
69        setDarkTheme(false);
70        setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(false /* opposite */));
71        setUseCallableUri(true);
72        sendScreenView();
73
74        try {
75            mActivityScrollListener = (OnListFragmentScrolledListener) activity;
76        } catch (ClassCastException e) {
77            throw new ClassCastException(activity.toString()
78                    + " must implement OnListFragmentScrolledListener");
79        }
80    }
81
82    @Override
83    public void onStart() {
84        super.onStart();
85        if (isSearchMode()) {
86            getAdapter().setHasHeader(0, false);
87        }
88
89        mActivity = (HostInterface) getActivity();
90
91        final Resources res = getResources();
92        mActionBarHeight = mActivity.getActionBarHeight();
93        mShadowHeight  = res.getDrawable(R.drawable.search_shadow).getIntrinsicHeight();
94        mPaddingTop = res.getDimensionPixelSize(R.dimen.search_list_padding_top);
95        mShowDialpadDuration = res.getInteger(R.integer.dialpad_slide_in_duration);
96        mHideDialpadDuration = res.getInteger(R.integer.dialpad_slide_out_duration);
97
98        final View parentView = getView();
99
100        final ListView listView = getListView();
101
102        listView.setBackgroundColor(res.getColor(R.color.background_dialer_results));
103        listView.setClipToPadding(false);
104        setVisibleScrollbarEnabled(false);
105        listView.setOnScrollListener(new OnScrollListener() {
106            @Override
107            public void onScrollStateChanged(AbsListView view, int scrollState) {
108                mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
109            }
110
111            @Override
112            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
113                    int totalItemCount) {
114            }
115        });
116
117        updatePosition(false /* animate */);
118    }
119
120    @Override
121    public void onViewCreated(View view, Bundle savedInstanceState) {
122        super.onViewCreated(view, savedInstanceState);
123        ViewUtil.addBottomPaddingToListViewForFab(getListView(), getResources());
124    }
125
126    @Override
127    protected void setSearchMode(boolean flag) {
128        super.setSearchMode(flag);
129        // This hides the "All contacts with phone numbers" header in the search fragment
130        final ContactEntryListAdapter adapter = getAdapter();
131        if (adapter != null) {
132            adapter.setHasHeader(0, false);
133        }
134    }
135
136    public void setAddToContactNumber(String addToContactNumber) {
137        mAddToContactNumber = addToContactNumber;
138    }
139
140    @Override
141    protected ContactEntryListAdapter createListAdapter() {
142        DialerPhoneNumberListAdapter adapter = new DialerPhoneNumberListAdapter(getActivity());
143        adapter.setDisplayPhotos(true);
144        adapter.setUseCallableUri(super.usesCallableUri());
145        return adapter;
146    }
147
148    @Override
149    protected void onItemClick(int position, long id) {
150        final DialerPhoneNumberListAdapter adapter = (DialerPhoneNumberListAdapter) getAdapter();
151        final int shortcutType = adapter.getShortcutTypeFromPosition(position);
152        final OnPhoneNumberPickerActionListener listener;
153
154        switch (shortcutType) {
155            case DialerPhoneNumberListAdapter.SHORTCUT_INVALID:
156                super.onItemClick(position, id);
157                break;
158            case DialerPhoneNumberListAdapter.SHORTCUT_DIRECT_CALL:
159                listener = getOnPhoneNumberPickerListener();
160                if (listener != null) {
161                    listener.onCallNumberDirectly(getQueryString());
162                }
163                break;
164            case DialerPhoneNumberListAdapter.SHORTCUT_ADD_NUMBER_TO_CONTACTS:
165                final String number = TextUtils.isEmpty(mAddToContactNumber) ?
166                        adapter.getFormattedQueryString() : mAddToContactNumber;
167                final Intent intent = DialtactsActivity.getAddNumberToContactIntent(number);
168                DialerUtils.startActivityWithErrorToast(getActivity(), intent,
169                        R.string.add_contact_not_available);
170                break;
171            case DialerPhoneNumberListAdapter.SHORTCUT_MAKE_VIDEO_CALL:
172                listener = getOnPhoneNumberPickerListener();
173                if (listener != null) {
174                    listener.onCallNumberDirectly(getQueryString(), true /* isVideoCall */);
175                }
176                break;
177        }
178    }
179
180    /**
181     * Updates the position and padding of the search fragment, depending on whether the dialpad is
182     * shown. This can be optionally animated.
183     * @param animate
184     */
185    public void updatePosition(boolean animate) {
186        // Use negative shadow height instead of 0 to account for the 9-patch's shadow.
187        int startTranslationValue =
188                mActivity.isDialpadShown() ? mActionBarHeight - mShadowHeight: -mShadowHeight;
189        int endTranslationValue = 0;
190        // Prevents ListView from being translated down after a rotation when the ActionBar is up.
191        if (animate || mActivity.isActionBarShowing()) {
192            endTranslationValue =
193                    mActivity.isDialpadShown() ? 0 : mActionBarHeight -mShadowHeight;
194        }
195        if (animate) {
196            Interpolator interpolator =
197                    mActivity.isDialpadShown() ? AnimUtils.EASE_IN : AnimUtils.EASE_OUT ;
198            int duration =
199                    mActivity.isDialpadShown() ? mShowDialpadDuration : mHideDialpadDuration;
200            getView().setTranslationY(startTranslationValue);
201            getView().animate()
202                    .translationY(endTranslationValue)
203                    .setInterpolator(interpolator)
204                    .setDuration(duration);
205        } else {
206            getView().setTranslationY(endTranslationValue);
207        }
208
209        // There is padding which should only be applied when the dialpad is not shown.
210        int paddingTop = mActivity.isDialpadShown() ? 0 : mPaddingTop;
211        final ListView listView = getListView();
212        listView.setPaddingRelative(
213                listView.getPaddingStart(),
214                paddingTop,
215                listView.getPaddingEnd(),
216                listView.getPaddingBottom());
217    }
218}
219