blob: 67c937c22807afab5490b1fbbd06e5c56cc3d0b0 [file] [log] [blame]
Brian Attwell20510ec2015-02-27 16:10:45 -08001/*
2 * Copyright (C) 2015 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.list;
18
Gary Mai967cffd2016-08-01 16:54:25 -070019import android.content.Context;
20import android.database.Cursor;
21import android.graphics.drawable.Drawable;
22import android.os.Bundle;
23import android.provider.ContactsContract;
24import android.support.v4.view.ViewCompat;
25import android.util.Log;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.view.accessibility.AccessibilityEvent;
30import android.view.animation.Animation;
31import android.view.animation.AnimationUtils;
32import android.widget.AbsListView;
33import android.widget.ImageView;
34import android.widget.TextView;
35
Wenyi Wang1114fde2016-07-11 21:44:02 -070036import com.android.contacts.R;
Wenyi Wang79675452016-08-17 10:43:28 -070037import com.android.contacts.activities.ActionBarAdapter;
Gary Mai0a49afa2016-12-05 15:53:58 -080038import com.android.contacts.group.GroupMembersFragment;
Gary Mai69c182a2016-12-05 13:07:03 -080039import com.android.contacts.list.MultiSelectEntryContactListAdapter.SelectedContactsListener;
40import com.android.contacts.logging.ListEvent.ActionType;
41import com.android.contacts.logging.Logger;
42import com.android.contacts.logging.SearchState;
43import com.android.contacts.model.AccountTypeManager;
44import com.android.contacts.model.account.AccountType;
45import com.android.contacts.model.account.AccountWithDataSet;
46import com.android.contacts.model.account.GoogleAccountType;
Brian Attwell20510ec2015-02-27 16:10:45 -080047
Walter Janga84fe612016-01-13 16:49:04 -080048import java.util.ArrayList;
49import java.util.List;
Brian Attwell20510ec2015-02-27 16:10:45 -080050import java.util.TreeSet;
51
52/**
53 * Fragment containing a contact list used for browsing contacts and optionally selecting
54 * multiple contacts via checkboxes.
55 */
Walter Jange9ea4f02016-05-10 09:39:46 -070056public abstract class MultiSelectContactsListFragment<T extends MultiSelectEntryContactListAdapter>
57 extends ContactEntryListFragment<T>
Brian Attwell20510ec2015-02-27 16:10:45 -080058 implements SelectedContactsListener {
59
Gary Mai967cffd2016-08-01 16:54:25 -070060 protected boolean mAnimateOnLoad;
Walter Jang9c1fa5d2016-05-17 09:04:40 -070061 private static final String TAG = "MultiContactsList";
62
Brian Attwell20510ec2015-02-27 16:10:45 -080063 public interface OnCheckBoxListActionListener {
64 void onStartDisplayingCheckBoxes();
65 void onSelectedContactIdsChanged();
Brian Attwell8f8937f2015-03-05 14:07:43 -080066 void onStopDisplayingCheckBoxes();
Brian Attwell20510ec2015-02-27 16:10:45 -080067 }
68
69 private static final String EXTRA_KEY_SELECTED_CONTACTS = "selected_contacts";
70
Walter Janga84fe612016-01-13 16:49:04 -080071 private static final String KEY_SEARCH_RESULT_CLICKED = "search_result_clicked";
72
Brian Attwell20510ec2015-02-27 16:10:45 -080073 private OnCheckBoxListActionListener mCheckBoxListListener;
Walter Janga84fe612016-01-13 16:49:04 -080074 private boolean mSearchResultClicked;
Brian Attwell20510ec2015-02-27 16:10:45 -080075
76 public void setCheckBoxListListener(OnCheckBoxListActionListener checkBoxListListener) {
77 mCheckBoxListListener = checkBoxListListener;
78 }
79
Walter Janga84fe612016-01-13 16:49:04 -080080 /**
81 * Whether a search result was clicked by the user. Tracked so that we can distinguish
Walter Jang9c1fa5d2016-05-17 09:04:40 -070082 * between exiting the search mode after a result was clicked from exiting w/o clicking
Walter Janga84fe612016-01-13 16:49:04 -080083 * any search result.
84 */
85 public boolean wasSearchResultClicked() {
86 return mSearchResultClicked;
87 }
88
89 /**
90 * Resets whether a search result was clicked by the user to false.
91 */
92 public void resetSearchResultClicked() {
93 mSearchResultClicked = false;
94 }
95
Gary Mai967cffd2016-08-01 16:54:25 -070096 public void setAnimateOnLoad(boolean shouldAnimate) {
97 mAnimateOnLoad = shouldAnimate;
98 }
99
Brian Attwell20510ec2015-02-27 16:10:45 -0800100 @Override
101 public void onSelectedContactsChanged() {
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700102 if (mCheckBoxListListener != null) mCheckBoxListListener.onSelectedContactIdsChanged();
Brian Attwell20510ec2015-02-27 16:10:45 -0800103 }
104
105 @Override
Gary Mai967cffd2016-08-01 16:54:25 -0700106 public View onCreateView(LayoutInflater inflater, ViewGroup container,
107 Bundle savedInstanceState) {
108 super.onCreateView(inflater, container, savedInstanceState);
109 if (savedInstanceState == null && mAnimateOnLoad) {
110 setLayoutAnimation(getListView(), R.anim.slide_and_fade_in_layout_animation);
111 }
112 return getView();
113 }
114
115 @Override
Brian Attwell20510ec2015-02-27 16:10:45 -0800116 public void onActivityCreated(Bundle savedInstanceState) {
117 super.onActivityCreated(savedInstanceState);
118 if (savedInstanceState != null) {
119 final TreeSet<Long> selectedContactIds = (TreeSet<Long>)
120 savedInstanceState.getSerializable(EXTRA_KEY_SELECTED_CONTACTS);
121 getAdapter().setSelectedContactIds(selectedContactIds);
Walter Janga84fe612016-01-13 16:49:04 -0800122 mSearchResultClicked = savedInstanceState.getBoolean(KEY_SEARCH_RESULT_CLICKED);
Brian Attwell20510ec2015-02-27 16:10:45 -0800123 }
124 }
125
Wenyi Wang6927bf32016-08-15 18:31:24 -0700126 @Override
127 public void onStart() {
128 super.onStart();
129 if (mCheckBoxListListener != null) {
130 mCheckBoxListListener.onSelectedContactIdsChanged();
131 }
132 }
133
Brian Attwell20510ec2015-02-27 16:10:45 -0800134 public TreeSet<Long> getSelectedContactIds() {
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700135 return getAdapter().getSelectedContactIds();
136 }
137
138 public long[] getSelectedContactIdsArray() {
139 return getAdapter().getSelectedContactIdsArray();
Brian Attwell20510ec2015-02-27 16:10:45 -0800140 }
141
142 @Override
Brian Attwell20510ec2015-02-27 16:10:45 -0800143 protected void configureAdapter() {
144 super.configureAdapter();
145 getAdapter().setSelectedContactsListener(this);
146 }
147
148 @Override
149 public void onSaveInstanceState(Bundle outState) {
150 super.onSaveInstanceState(outState);
151 outState.putSerializable(EXTRA_KEY_SELECTED_CONTACTS, getSelectedContactIds());
Walter Janga84fe612016-01-13 16:49:04 -0800152 outState.putBoolean(KEY_SEARCH_RESULT_CLICKED, mSearchResultClicked);
Brian Attwell20510ec2015-02-27 16:10:45 -0800153 }
154
155 public void displayCheckBoxes(boolean displayCheckBoxes) {
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700156 if (getAdapter() != null) {
157 getAdapter().setDisplayCheckBoxes(displayCheckBoxes);
158 if (!displayCheckBoxes) {
159 clearCheckBoxes();
160 }
Brian Attwell20510ec2015-02-27 16:10:45 -0800161 }
162 }
Brian Attwelld2962a32015-03-02 14:48:50 -0800163
164 public void clearCheckBoxes() {
165 getAdapter().setSelectedContactIds(new TreeSet<Long>());
166 }
167
Brian Attwell20510ec2015-02-27 16:10:45 -0800168 @Override
169 protected boolean onItemLongClick(int position, long id) {
Brian Attwell8f8937f2015-03-05 14:07:43 -0800170 final int previouslySelectedCount = getAdapter().getSelectedContactIds().size();
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700171 final long contactId = getContactId(position);
Tingting Wang80dfab32015-07-29 14:42:40 -0700172 final int partition = getAdapter().getPartitionForPosition(position);
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700173 if (contactId >= 0 && partition == ContactsContract.Directory.DEFAULT) {
174 if (mCheckBoxListListener != null) {
175 mCheckBoxListListener.onStartDisplayingCheckBoxes();
176 }
177 getAdapter().toggleSelectionOfContactId(contactId);
Wenyi Wang2b943992016-05-20 17:21:35 -0700178 Logger.logListEvent(ActionType.SELECT, getListType(),
179 /* count */ getAdapter().getCount(), /* clickedIndex */ position,
180 /* numSelected */ 1);
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700181 // Manually send clicked event if there is a checkbox.
Wenyi Wang2b943992016-05-20 17:21:35 -0700182 // See b/24098561. TalkBack will not read it otherwise.
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700183 final int index = position + getListView().getHeaderViewsCount() - getListView()
184 .getFirstVisiblePosition();
185 if (index >= 0 && index < getListView().getChildCount()) {
186 getListView().getChildAt(index).sendAccessibilityEvent(AccessibilityEvent
187 .TYPE_VIEW_CLICKED);
Brian Attwellc00112f2015-03-02 18:32:35 -0800188 }
Brian Attwell20510ec2015-02-27 16:10:45 -0800189 }
Brian Attwell8f8937f2015-03-05 14:07:43 -0800190 final int nowSelectedCount = getAdapter().getSelectedContactIds().size();
191 if (mCheckBoxListListener != null
192 && previouslySelectedCount != 0 && nowSelectedCount == 0) {
193 // Last checkbox has been unchecked. So we should stop displaying checkboxes.
194 mCheckBoxListListener.onStopDisplayingCheckBoxes();
195 }
Brian Attwell20510ec2015-02-27 16:10:45 -0800196 return true;
197 }
198
199 @Override
200 protected void onItemClick(int position, long id) {
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700201 final long contactId = getContactId(position);
202 if (contactId < 0) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800203 return;
204 }
205 if (getAdapter().isDisplayingCheckBoxes()) {
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700206 getAdapter().toggleSelectionOfContactId(contactId);
Brian Attwell20510ec2015-02-27 16:10:45 -0800207 } else {
Walter Jang82c90332016-02-24 17:34:34 -0800208 if (isSearchMode()) {
209 mSearchResultClicked = true;
210 Logger.logSearchEvent(createSearchStateForSearchResultClick(position));
211 }
Brian Attwell20510ec2015-02-27 16:10:45 -0800212 }
Brian Attwell8f8937f2015-03-05 14:07:43 -0800213 if (mCheckBoxListListener != null && getAdapter().getSelectedContactIds().size() == 0) {
214 mCheckBoxListListener.onStopDisplayingCheckBoxes();
215 }
Brian Attwell20510ec2015-02-27 16:10:45 -0800216 }
217
Walter Jang9c1fa5d2016-05-17 09:04:40 -0700218 private long getContactId(int position) {
219 final int contactIdColumnIndex = getAdapter().getContactColumnIdIndex();
220
221 final Cursor cursor = (Cursor) getAdapter().getItem(position);
222 if (cursor != null) {
223 if (cursor.getColumnCount() > contactIdColumnIndex) {
224 return cursor.getLong(contactIdColumnIndex);
225 }
226 }
227
228 Log.w(TAG, "Failed to get contact ID from cursor column " + contactIdColumnIndex);
229 return -1;
230 }
231
Walter Janga84fe612016-01-13 16:49:04 -0800232 /**
233 * Returns the state of the search results currently presented to the user.
234 */
235 public SearchState createSearchState() {
236 return createSearchState(/* selectedPosition */ -1);
237 }
238
239 /**
240 * Returns the state of the search results presented to the user
241 * at the time the result in the given position was clicked.
242 */
243 public SearchState createSearchStateForSearchResultClick(int selectedPosition) {
244 return createSearchState(selectedPosition);
245 }
246
247 private SearchState createSearchState(int selectedPosition) {
248 final MultiSelectEntryContactListAdapter adapter = getAdapter();
249 if (adapter == null) {
250 return null;
251 }
252 final SearchState searchState = new SearchState();
253 searchState.queryLength = adapter.getQueryString() == null
254 ? 0 : adapter.getQueryString().length();
255 searchState.numPartitions = adapter.getPartitionCount();
256
257 // Set the number of results displayed to the user. Note that the adapter.getCount(),
258 // value does not always match the number of results actually displayed to the user,
259 // which is why we calculate it manually.
260 final List<Integer> numResultsInEachPartition = new ArrayList<>();
261 for (int i = 0; i < adapter.getPartitionCount(); i++) {
262 final Cursor cursor = adapter.getCursor(i);
263 if (cursor == null || cursor.isClosed()) {
264 // Something went wrong, abort.
265 numResultsInEachPartition.clear();
266 break;
267 }
268 numResultsInEachPartition.add(cursor.getCount());
269 }
270 if (!numResultsInEachPartition.isEmpty()) {
271 int numResults = 0;
272 for (int i = 0; i < numResultsInEachPartition.size(); i++) {
273 numResults += numResultsInEachPartition.get(i);
274 }
275 searchState.numResults = numResults;
276 }
277
278 // If a selection was made, set additional search state
279 if (selectedPosition >= 0) {
280 searchState.selectedPartition = adapter.getPartitionForPosition(selectedPosition);
281 searchState.selectedIndexInPartition = adapter.getOffsetInPartition(selectedPosition);
282 final Cursor cursor = adapter.getCursor(searchState.selectedPartition);
283 searchState.numResultsInSelectedPartition =
284 cursor == null || cursor.isClosed() ? -1 : cursor.getCount();
285
286 // Calculate the index across all partitions
287 if (!numResultsInEachPartition.isEmpty()) {
288 int selectedIndex = 0;
289 for (int i = 0; i < searchState.selectedPartition; i++) {
290 selectedIndex += numResultsInEachPartition.get(i);
291 }
292 selectedIndex += searchState.selectedIndexInPartition;
293 searchState.selectedIndex = selectedIndex;
294 }
295 }
296 return searchState;
297 }
Wenyi Wang1114fde2016-07-11 21:44:02 -0700298
Gary Mai967cffd2016-08-01 16:54:25 -0700299 protected void setLayoutAnimation(final ViewGroup view, int animationId) {
300 if (view == null) {
301 return;
302 }
303 view.setLayoutAnimationListener(new Animation.AnimationListener() {
304 @Override
305 public void onAnimationStart(Animation animation) {
306 }
307
308 @Override
309 public void onAnimationEnd(Animation animation) {
310 view.setLayoutAnimation(null);
311 }
312
313 @Override
314 public void onAnimationRepeat(Animation animation) {
315 }
316 });
317 view.setLayoutAnimation(AnimationUtils.loadLayoutAnimation(getActivity(), animationId));
318 }
319
Wenyi Wang1114fde2016-07-11 21:44:02 -0700320 @Override
321 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
322 int totalItemCount) {
323 final View accountFilterContainer = getView().findViewById(
324 R.id.account_filter_header_container);
325 if (accountFilterContainer == null) {
326 return;
327 }
Wenyi Wang141b8372016-08-03 11:13:10 -0700328
329 int firstCompletelyVisibleItem = firstVisibleItem;
330 if (view != null && view.getChildAt(0) != null && view.getChildAt(0).getTop() < 0) {
331 firstCompletelyVisibleItem++;
332 }
333
334 if (firstCompletelyVisibleItem == 0) {
Wenyi Wang81067f52016-07-26 18:18:11 -0700335 ViewCompat.setElevation(accountFilterContainer, 0);
Wenyi Wang1114fde2016-07-11 21:44:02 -0700336 } else {
Wenyi Wang81067f52016-07-26 18:18:11 -0700337 ViewCompat.setElevation(accountFilterContainer,
338 getResources().getDimension(R.dimen.contact_list_header_elevation));
Wenyi Wang1114fde2016-07-11 21:44:02 -0700339 }
340 }
341
Walter Jang92942632016-07-14 19:49:32 +0000342 protected void bindListHeaderCustom(View listView, View accountFilterContainer) {
343 bindListHeaderCommon(listView, accountFilterContainer);
344
345 final TextView accountFilterHeader = (TextView) accountFilterContainer.findViewById(
346 R.id.account_filter_header);
347 accountFilterHeader.setText(R.string.listCustomView);
348 accountFilterHeader.setAllCaps(false);
349
350 final ImageView accountFilterHeaderIcon = (ImageView) accountFilterContainer
351 .findViewById(R.id.account_filter_icon);
Wenyi Wang20db9852016-07-18 18:41:41 -0700352 accountFilterHeaderIcon.setVisibility(View.GONE);
Walter Jang92942632016-07-14 19:49:32 +0000353 }
354
Wenyi Wang1114fde2016-07-11 21:44:02 -0700355 /**
356 * Show account icon, count of contacts and account name in the header of the list.
357 */
358 protected void bindListHeader(Context context, View listView, View accountFilterContainer,
359 AccountWithDataSet accountWithDataSet, int memberCount) {
360 if (memberCount < 0) {
361 hideHeaderAndAddPadding(context, listView, accountFilterContainer);
362 return;
363 }
364
Walter Jang92942632016-07-14 19:49:32 +0000365 bindListHeaderCommon(listView, accountFilterContainer);
Wenyi Wang1114fde2016-07-11 21:44:02 -0700366
Wenyi Wang96fb8b52016-11-07 14:12:11 -0800367 final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
368 final AccountType accountType = accountTypeManager.getAccountType(
369 accountWithDataSet.type, accountWithDataSet.dataSet);
370
371 // Set text of count of contacts and account name
Wenyi Wang1114fde2016-07-11 21:44:02 -0700372 final TextView accountFilterHeader = (TextView) accountFilterContainer.findViewById(
373 R.id.account_filter_header);
Wenyi Wang96fb8b52016-11-07 14:12:11 -0800374 final String headerText = shouldShowAccountName(accountType)
Wenyi Wang3d8803e2016-07-18 14:29:37 -0700375 ? String.format(context.getResources().getQuantityString(
376 R.plurals.contacts_count_with_account, memberCount),
377 memberCount, accountWithDataSet.name)
378 : context.getResources().getQuantityString(
379 R.plurals.contacts_count, memberCount, memberCount);
380 accountFilterHeader.setText(headerText);
Wenyi Wang1114fde2016-07-11 21:44:02 -0700381 accountFilterHeader.setAllCaps(false);
382
383 // Set icon of the account
Wenyi Wang1114fde2016-07-11 21:44:02 -0700384 final Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
385 final ImageView accountFilterHeaderIcon = (ImageView) accountFilterContainer
386 .findViewById(R.id.account_filter_icon);
Wenyi Wang81067f52016-07-26 18:18:11 -0700387
388 // If it's a writable Google account, we set icon size as 24dp; otherwise, we set it as
389 // 20dp. And we need to change margin accordingly. This is because the Google icon looks
390 // smaller when the icons are of the same size.
391 if (accountType instanceof GoogleAccountType) {
392 accountFilterHeaderIcon.getLayoutParams().height = getResources()
393 .getDimensionPixelOffset(R.dimen.contact_browser_list_header_icon_size);
Wenyi Wang6c46e5b2016-11-17 10:57:42 -0800394 accountFilterHeaderIcon.getLayoutParams().width = getResources()
395 .getDimensionPixelOffset(R.dimen.contact_browser_list_header_icon_size);
Wenyi Wang81067f52016-07-26 18:18:11 -0700396
397 setMargins(accountFilterHeaderIcon,
398 getResources().getDimensionPixelOffset(
399 R.dimen.contact_browser_list_header_icon_left_margin),
400 getResources().getDimensionPixelOffset(
401 R.dimen.contact_browser_list_header_icon_right_margin));
402 } else {
403 accountFilterHeaderIcon.getLayoutParams().height = getResources()
404 .getDimensionPixelOffset(R.dimen.contact_browser_list_header_icon_size_alt);
Wenyi Wang6c46e5b2016-11-17 10:57:42 -0800405 accountFilterHeaderIcon.getLayoutParams().width = getResources()
406 .getDimensionPixelOffset(R.dimen.contact_browser_list_header_icon_size_alt);
Wenyi Wang81067f52016-07-26 18:18:11 -0700407
408 setMargins(accountFilterHeaderIcon,
409 getResources().getDimensionPixelOffset(
410 R.dimen.contact_browser_list_header_icon_left_margin_alt),
411 getResources().getDimensionPixelOffset(
412 R.dimen.contact_browser_list_header_icon_right_margin_alt));
413 }
414 accountFilterHeaderIcon.requestLayout();
415
Walter Jang92942632016-07-14 19:49:32 +0000416 accountFilterHeaderIcon.setVisibility(View.VISIBLE);
Wenyi Wang1114fde2016-07-11 21:44:02 -0700417 accountFilterHeaderIcon.setImageDrawable(icon);
418 }
419
Wenyi Wang96fb8b52016-11-07 14:12:11 -0800420 private boolean shouldShowAccountName(AccountType accountType) {
421 return (accountType.isGroupMembershipEditable() && this instanceof GroupMembersFragment)
422 || GoogleAccountType.ACCOUNT_TYPE.equals(accountType.accountType);
423 }
424
Wenyi Wang81067f52016-07-26 18:18:11 -0700425 private void setMargins(View v, int l, int r) {
426 if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
427 ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
428 p.setMarginStart(l);
429 p.setMarginEnd(r);
430 v.setLayoutParams(p);
431 v.requestLayout();
432 }
433 }
434
Walter Jang92942632016-07-14 19:49:32 +0000435 private void bindListHeaderCommon(View listView, View accountFilterContainer) {
436 // Show header and remove top padding of the list
437 accountFilterContainer.setVisibility(View.VISIBLE);
Wenyi Wang7cd9af32016-07-17 16:00:43 -0700438 setListViewPaddingTop(listView, /* paddingTop */ 0);
Walter Jang92942632016-07-14 19:49:32 +0000439 }
440
Wenyi Wang1114fde2016-07-11 21:44:02 -0700441 /**
442 * Hide header of list view and add padding to the top of list view.
443 */
444 protected void hideHeaderAndAddPadding(Context context, View listView,
445 View accountFilterContainer) {
446 accountFilterContainer.setVisibility(View.GONE);
Wenyi Wang7cd9af32016-07-17 16:00:43 -0700447 setListViewPaddingTop(listView,
448 /* paddingTop */ context.getResources().getDimensionPixelSize(
449 R.dimen.contact_browser_list_item_padding_top_or_bottom));
450 }
451
452 private void setListViewPaddingTop(View listView, int paddingTop) {
453 listView.setPadding(listView.getPaddingLeft(), paddingTop, listView.getPaddingRight(),
454 listView.getPaddingBottom());
Wenyi Wang1114fde2016-07-11 21:44:02 -0700455 }
456
Wenyi Wang79675452016-08-17 10:43:28 -0700457 /**
458 * Returns the {@link ActionBarAdapter} object associated with list fragment.
459 */
460 public ActionBarAdapter getActionBarAdapter() {
461 return null;
462 }
Brian Attwell20510ec2015-02-27 16:10:45 -0800463}