1 /*
2  * Copyright (C) 2017 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 
17 package com.android.car.dialer.ui.search;
18 
19 import android.os.Bundle;
20 import android.text.TextUtils;
21 import android.view.View;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 import androidx.fragment.app.Fragment;
26 import androidx.lifecycle.ViewModelProviders;
27 import androidx.recyclerview.widget.RecyclerView;
28 
29 import com.android.car.dialer.R;
30 import com.android.car.dialer.log.L;
31 import com.android.car.dialer.ui.common.DialerListBaseFragment;
32 import com.android.car.dialer.ui.contact.ContactDetailsFragment;
33 import com.android.car.telephony.common.Contact;
34 import com.android.car.ui.toolbar.Toolbar;
35 import com.android.car.ui.toolbar.ToolbarController;
36 
37 /**
38  * A fragment that will take a search query, look up contacts that match and display those
39  * results as a list.
40  */
41 public class ContactResultsFragment extends DialerListBaseFragment implements
42         ContactResultsAdapter.OnShowContactDetailListener, Toolbar.OnSearchListener {
43 
44     /**
45      * Creates a new instance of the {@link ContactResultsFragment}.
46      *
47      * @param initialSearchQuery An optional search query that will be inputted when the fragment
48      *                           starts up.
49      */
newInstance(@ullable String initialSearchQuery)50     public static ContactResultsFragment newInstance(@Nullable String initialSearchQuery) {
51         ContactResultsFragment fragment = new ContactResultsFragment();
52         Bundle args = new Bundle();
53         args.putString(SEARCH_QUERY, initialSearchQuery);
54         fragment.setArguments(args);
55         return fragment;
56     }
57 
58     public static final String FRAGMENT_TAG = "ContactResultsFragment";
59 
60     private static final String TAG = "CD.ContactResultsFragment";
61     private static final String SEARCH_QUERY = "SearchQuery";
62 
63     private ContactResultsViewModel mContactResultsViewModel;
64     private final ContactResultsAdapter mAdapter = new ContactResultsAdapter(this);
65 
66     private RecyclerView.OnScrollListener mOnScrollChangeListener;
67     private ToolbarController mToolbar;
68 
69     @Override
onCreate(Bundle savedInstanceState)70     public void onCreate(Bundle savedInstanceState) {
71         super.onCreate(savedInstanceState);
72 
73         mContactResultsViewModel = ViewModelProviders.of(this).get(
74                 ContactResultsViewModel.class);
75         mContactResultsViewModel.getContactSearchResults().observe(this,
76                 contactResults -> {
77                     mAdapter.setData(contactResults);
78                     showContent();
79                 });
80 
81         // Set the initial search query, if one was provided from a Intent.ACTION_SEARCH
82         if (getArguments() != null) {
83             String initialQuery = getArguments().getString(SEARCH_QUERY);
84             if (!TextUtils.isEmpty(initialQuery)) {
85                 setSearchQuery(initialQuery);
86             }
87             getArguments().clear();
88         }
89     }
90 
91     @Override
onViewCreated(View view, Bundle savedInstanceState)92     public void onViewCreated(View view, Bundle savedInstanceState) {
93         super.onViewCreated(view, savedInstanceState);
94         getRecyclerView().setAdapter(mAdapter);
95 
96         mOnScrollChangeListener = new RecyclerView.OnScrollListener() {
97             @Override
98             public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
99             }
100 
101             @Override
102             public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
103                 if (dy != 0) {
104                     // Clear the focus to dismiss the keyboard.
105                     getActivity().getCurrentFocus().clearFocus();
106                 }
107             }
108         };
109         getRecyclerView().addOnScrollListener(mOnScrollChangeListener);
110     }
111 
112     @Override
onDestroyView()113     public void onDestroyView() {
114         super.onDestroyView();
115         getRecyclerView().removeOnScrollListener(mOnScrollChangeListener);
116     }
117 
118     @Override
setupToolbar(@onNull ToolbarController toolbar)119     protected void setupToolbar(@NonNull ToolbarController toolbar) {
120         super.setupToolbar(toolbar);
121         mToolbar = toolbar;
122         mToolbar.registerOnSearchListener(this);
123         mToolbar.setSearchIcon(R.drawable.ic_app_icon);
124         setSearchQuery(mContactResultsViewModel.getSearchQuery());
125     }
126 
127     @Override
onStop()128     public void onStop() {
129         super.onStop();
130         mToolbar.unregisterOnSearchListener(this);
131     }
132 
133     /** Sets the search query that should be used to filter contacts. */
setSearchQuery(String query)134     public void setSearchQuery(String query) {
135         if (mToolbar != null) {
136             mToolbar.setSearchQuery(query);
137         } else {
138             onSearch(query);
139         }
140     }
141 
142     /** Triggered by search view text change. */
143     @Override
onSearch(String newQuery)144     public void onSearch(String newQuery) {
145         L.d(TAG, "onSearch: %s", newQuery);
146         mContactResultsViewModel.setSearchQuery(newQuery);
147     }
148 
149     @Override
onShowContactDetail(Contact contact)150     public void onShowContactDetail(Contact contact) {
151         Fragment contactDetailsFragment = ContactDetailsFragment.newInstance(contact);
152         pushContentFragment(contactDetailsFragment, ContactDetailsFragment.FRAGMENT_TAG);
153     }
154 
155     @Override
getToolbarState()156     protected Toolbar.State getToolbarState() {
157         return Toolbar.State.SEARCH;
158     }
159 }
160