• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.settings.datetime.timezone;
18 
19 import android.os.Bundle;
20 import android.view.LayoutInflater;
21 import android.view.Menu;
22 import android.view.MenuInflater;
23 import android.view.MenuItem;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.widget.LinearLayout;
27 import android.widget.SearchView;
28 import android.widget.TextView;
29 
30 import androidx.annotation.NonNull;
31 import androidx.coordinatorlayout.widget.CoordinatorLayout;
32 import androidx.core.view.ViewCompat;
33 import androidx.recyclerview.widget.LinearLayoutManager;
34 import androidx.recyclerview.widget.RecyclerView;
35 
36 import com.android.settings.R;
37 import com.android.settings.core.InstrumentedFragment;
38 import com.android.settings.datetime.timezone.model.TimeZoneData;
39 import com.android.settings.datetime.timezone.model.TimeZoneDataLoader;
40 
41 import com.google.android.material.appbar.AppBarLayout;
42 
43 import java.util.Locale;
44 
45 /**
46  * It's abstract class. Subclass should use it with {@class BaseTimeZoneAdapter} and
47  * {@class AdapterItem} to provide a list view with text search capability.
48  * The search matches the prefix of words in the search text.
49  */
50 public abstract class BaseTimeZonePicker extends InstrumentedFragment
51         implements SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener {
52 
53     public static final String EXTRA_RESULT_REGION_ID =
54             "com.android.settings.datetime.timezone.result_region_id";
55     public static final String EXTRA_RESULT_TIME_ZONE_ID =
56             "com.android.settings.datetime.timezone.result_time_zone_id";
57 
58     protected AppBarLayout mAppBarLayout;
59 
60     private final int mTitleResId;
61     private final int mSearchHintResId;
62     private final boolean mSearchEnabled;
63     private final boolean mDefaultExpandSearch;
64 
65     protected Locale mLocale;
66     private BaseTimeZoneAdapter mAdapter;
67     private RecyclerView mRecyclerView;
68     private TimeZoneData mTimeZoneData;
69 
70     private SearchView mSearchView;
71 
72     /**
73      * Constructor called by subclass.
74      * @param defaultExpandSearch whether expand the search view when first launching the fragment
75      */
BaseTimeZonePicker(int titleResId, int searchHintResId, boolean searchEnabled, boolean defaultExpandSearch)76     protected BaseTimeZonePicker(int titleResId, int searchHintResId,
77             boolean searchEnabled, boolean defaultExpandSearch) {
78         mTitleResId = titleResId;
79         mSearchHintResId = searchHintResId;
80         mSearchEnabled = searchEnabled;
81         mDefaultExpandSearch = defaultExpandSearch;
82     }
83 
84     @Override
onCreate(Bundle savedInstanceState)85     public void onCreate(Bundle savedInstanceState) {
86         super.onCreate(savedInstanceState);
87         setHasOptionsMenu(true);
88         getActivity().setTitle(mTitleResId);
89     }
90 
91     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)92     public View onCreateView(LayoutInflater inflater, ViewGroup container,
93             Bundle savedInstanceState) {
94         final View view = inflater.inflate(R.layout.recycler_view, container, false);
95         mRecyclerView = view.findViewById(R.id.recycler_view);
96         mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(),
97                 LinearLayoutManager.VERTICAL, /* reverseLayout */ false));
98         mRecyclerView.setAdapter(mAdapter);
99         mAppBarLayout = getActivity().findViewById(R.id.app_bar);
100         disableToolBarScrollableBehavior();
101 
102         // Initialize TimeZoneDataLoader only when mRecyclerView is ready to avoid race
103         // during onDateLoaderReady callback.
104         getLoaderManager().initLoader(0, null, new TimeZoneDataLoader.LoaderCreator(
105                 getContext(), this::onTimeZoneDataReady));
106         return view;
107     }
108 
onTimeZoneDataReady(TimeZoneData timeZoneData)109     public void onTimeZoneDataReady(TimeZoneData timeZoneData) {
110         if (mTimeZoneData == null && timeZoneData != null) {
111             mTimeZoneData = timeZoneData;
112             mAdapter = createAdapter(mTimeZoneData);
113             if (mRecyclerView != null) {
114                 mRecyclerView.setAdapter(mAdapter);
115             }
116         }
117     }
118 
getLocale()119     protected Locale getLocale() {
120         return getContext().getResources().getConfiguration().getLocales().get(0);
121     }
122 
123     /**
124      * Called when TimeZoneData is ready.
125      */
createAdapter(TimeZoneData timeZoneData)126     protected abstract BaseTimeZoneAdapter createAdapter(TimeZoneData timeZoneData);
127 
128     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)129     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
130         if (mSearchEnabled) {
131             inflater.inflate(R.menu.time_zone_base_search_menu, menu);
132 
133             final MenuItem searchMenuItem = menu.findItem(R.id.time_zone_search_menu);
134             searchMenuItem.setOnActionExpandListener(this);
135             mSearchView = (SearchView) searchMenuItem.getActionView();
136 
137             mSearchView.setQueryHint(getText(mSearchHintResId));
138             mSearchView.setOnQueryTextListener(this);
139             mSearchView.setMaxWidth(Integer.MAX_VALUE);
140 
141             if (mDefaultExpandSearch) {
142                 searchMenuItem.expandActionView();
143                 mSearchView.setIconified(false);
144                 mSearchView.setActivated(true);
145                 mSearchView.setQuery("", true /* submit */);
146             }
147 
148             // Set zero margin and padding to align with the text horizontally in the preference
149             final TextView searchViewView = (TextView) mSearchView.findViewById(
150                     com.android.internal.R.id.search_src_text);
151             searchViewView.setPadding(0, searchViewView.getPaddingTop(), 0,
152                     searchViewView.getPaddingBottom());
153             final View editFrame = mSearchView.findViewById(
154                     com.android.internal.R.id.search_edit_frame);
155             final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) editFrame
156                     .getLayoutParams();
157             params.setMarginStart(0);
158             params.setMarginEnd(0);
159             editFrame.setLayoutParams(params);
160         }
161     }
162 
163     @Override
onMenuItemActionExpand(MenuItem item)164     public boolean onMenuItemActionExpand(MenuItem item) {
165         // To prevent a large space on tool bar.
166         mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);
167         // To prevent user can expand the collapsing tool bar view.
168         ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);
169         return true;
170     }
171 
172     @Override
onMenuItemActionCollapse(MenuItem item)173     public boolean onMenuItemActionCollapse(MenuItem item) {
174         // We keep the collapsed status after user cancel the search function.
175         mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);
176         ViewCompat.setNestedScrollingEnabled(mRecyclerView, true);
177         return true;
178     }
179 
180     @Override
onQueryTextSubmit(String query)181     public boolean onQueryTextSubmit(String query) {
182         return false;
183     }
184 
185     @Override
onQueryTextChange(String newText)186     public boolean onQueryTextChange(String newText) {
187         if (mAdapter != null) {
188             mAdapter.getFilter().filter(newText);
189         }
190         return false;
191     }
192 
193     public interface OnListItemClickListener<T extends BaseTimeZoneAdapter.AdapterItem> {
onListItemClick(T item)194         void onListItemClick(T item);
195     }
196 
disableToolBarScrollableBehavior()197     private void disableToolBarScrollableBehavior() {
198         CoordinatorLayout.LayoutParams params =
199                 (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
200         AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
201         behavior.setDragCallback(
202                 new AppBarLayout.Behavior.DragCallback() {
203                     @Override
204                     public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
205                         return false;
206                     }
207                 });
208         params.setBehavior(behavior);
209     }
210 }
211