blob: 54e7df258e0c84c3444da751a5cf01728953a300 [file] [log] [blame]
Yorke Lee6b049122013-07-16 10:38:02 -07001/*
Yorke Leedfb2eee2013-06-26 18:24:32 -07002 * Copyright (C) 2013 The Android Open Source Project
Yorke Lee6b049122013-07-16 10:38:02 -07003 *
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.dialer;
18
Yorke Leedfb2eee2013-06-26 18:24:32 -070019import android.animation.Animator;
20import android.animation.Animator.AnimatorListener;
21import android.animation.AnimatorListenerAdapter;
Yorke Lee6b049122013-07-16 10:38:02 -070022import android.app.Activity;
23import android.app.backup.BackupManager;
24import android.app.Fragment;
25import android.app.FragmentManager;
26import android.app.FragmentTransaction;
27import android.content.ActivityNotFoundException;
28import android.content.Context;
29import android.content.Intent;
30import android.content.SharedPreferences;
Yorke Leed9999322013-07-19 09:22:03 -070031import android.content.res.Resources;
Yorke Lee6b049122013-07-16 10:38:02 -070032import android.net.Uri;
33import android.os.Bundle;
34import android.os.RemoteException;
35import android.os.ServiceManager;
Yorke Lee6b049122013-07-16 10:38:02 -070036import android.provider.CallLog.Calls;
Yorke Leedfb2eee2013-06-26 18:24:32 -070037import android.provider.ContactsContract;
Yorke Lee6b049122013-07-16 10:38:02 -070038import android.provider.ContactsContract.Contacts;
39import android.provider.ContactsContract.Intents.UI;
Yorke Leedfb2eee2013-06-26 18:24:32 -070040import android.provider.Settings;
Yorke Leed9999322013-07-19 09:22:03 -070041import android.text.Editable;
Yorke Lee6b049122013-07-16 10:38:02 -070042import android.text.TextUtils;
Yorke Leed9999322013-07-19 09:22:03 -070043import android.text.TextWatcher;
Yorke Lee6b049122013-07-16 10:38:02 -070044import android.util.Log;
45import android.view.Menu;
Yorke Lee6b049122013-07-16 10:38:02 -070046import android.view.MenuItem;
Yorke Lee6b049122013-07-16 10:38:02 -070047import android.view.View;
Yorke Lee6b049122013-07-16 10:38:02 -070048import android.view.View.OnFocusChangeListener;
49import android.view.ViewConfiguration;
Yorke Lee6b049122013-07-16 10:38:02 -070050import android.view.inputmethod.InputMethodManager;
Yorke Leedfb2eee2013-06-26 18:24:32 -070051import android.widget.AbsListView.OnScrollListener;
Yorke Leed9999322013-07-19 09:22:03 -070052import android.widget.EditText;
53import android.widget.ImageView;
Yorke Lee6b049122013-07-16 10:38:02 -070054import android.widget.PopupMenu;
55import android.widget.SearchView;
56import android.widget.SearchView.OnCloseListener;
57import android.widget.SearchView.OnQueryTextListener;
58import android.widget.Toast;
59
60import com.android.contacts.common.CallUtil;
61import com.android.contacts.common.activity.TransactionSafeActivity;
Yorke Leedfb2eee2013-06-26 18:24:32 -070062import com.android.contacts.common.dialog.ClearFrequentsDialog;
63import com.android.contacts.common.interactions.ImportExportDialogFragment;
Yorke Lee6b049122013-07-16 10:38:02 -070064import com.android.contacts.common.list.ContactListItemView;
65import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
66import com.android.contacts.common.list.PhoneNumberPickerFragment;
Yorke Leedfb2eee2013-06-26 18:24:32 -070067import com.android.dialer.calllog.NewCallLogActivity;
68import com.android.dialer.dialpad.NewDialpadFragment;
69import com.android.dialer.dialpad.SmartDialNameMatcher;
Yorke Lee6b049122013-07-16 10:38:02 -070070import com.android.dialer.interactions.PhoneNumberInteraction;
Yorke Leedfb2eee2013-06-26 18:24:32 -070071import com.android.dialer.list.NewPhoneFavoriteFragment;
72import com.android.dialer.list.OnListFragmentScrolledListener;
73import com.android.dialer.list.SmartDialSearchFragment;
Yorke Lee6b049122013-07-16 10:38:02 -070074import com.android.internal.telephony.ITelephony;
75
76/**
Yorke Lee6b049122013-07-16 10:38:02 -070077 * The dialer tab's title is 'phone', a more common name (see strings.xml).
Yorke Leedfb2eee2013-06-26 18:24:32 -070078 *
79 * TODO krelease: All classes currently prefixed with New will replace the original classes or
80 * be renamed more appropriately before shipping.
Yorke Lee6b049122013-07-16 10:38:02 -070081 */
Yorke Leedfb2eee2013-06-26 18:24:32 -070082public class NewDialtactsActivity extends TransactionSafeActivity implements View.OnClickListener,
83 NewDialpadFragment.OnDialpadQueryChangedListener, PopupMenu.OnMenuItemClickListener,
84 OnListFragmentScrolledListener,
85 NewPhoneFavoriteFragment.OnPhoneFavoriteFragmentStartedListener {
Yorke Lee6b049122013-07-16 10:38:02 -070086 private static final String TAG = "DialtactsActivity";
87
88 public static final boolean DEBUG = false;
89
90 /** Used to open Call Setting */
91 private static final String PHONE_PACKAGE = "com.android.phone";
92 private static final String CALL_SETTINGS_CLASS_NAME =
93 "com.android.phone.CallFeaturesSetting";
94
95 /** @see #getCallOrigin() */
96 private static final String CALL_ORIGIN_DIALTACTS =
97 "com.android.dialer.DialtactsActivity";
98
Yorke Leedfb2eee2013-06-26 18:24:32 -070099 private static final String TAG_DIALPAD_FRAGMENT = "dialpad";
100 private static final String TAG_REGULAR_SEARCH_FRAGMENT = "search";
101 private static final String TAG_SMARTDIAL_SEARCH_FRAGMENT = "smartdial";
102 private static final String TAG_FAVORITES_FRAGMENT = "favorites";
103
Yorke Lee6b049122013-07-16 10:38:02 -0700104 /**
105 * Just for backward compatibility. Should behave as same as {@link Intent#ACTION_DIAL}.
106 */
107 private static final String ACTION_TOUCH_DIALER = "com.android.phone.action.TOUCH_DIALER";
108
Yorke Lee6b049122013-07-16 10:38:02 -0700109 private SharedPreferences mPrefs;
110
111 public static final String SHARED_PREFS_NAME = "com.android.dialer_preferences";
112
113 /** Last manually selected tab index */
114 private static final String PREF_LAST_MANUALLY_SELECTED_TAB =
115 "DialtactsActivity_last_manually_selected_tab";
Yorke Lee6b049122013-07-16 10:38:02 -0700116
117 private static final int SUBACTIVITY_ACCOUNT_FILTER = 1;
118
Yorke Lee6b049122013-07-16 10:38:02 -0700119 private String mFilterText;
120
Yorke Leedfb2eee2013-06-26 18:24:32 -0700121 /**
122 * The main fragment displaying the user's favorites and frequent contacts
123 */
124 private NewPhoneFavoriteFragment mPhoneFavoriteFragment;
Yorke Lee6b049122013-07-16 10:38:02 -0700125
126 /**
Yorke Leedfb2eee2013-06-26 18:24:32 -0700127 * Fragment containing the dialpad that slides into view
Yorke Lee6b049122013-07-16 10:38:02 -0700128 */
Yorke Leedfb2eee2013-06-26 18:24:32 -0700129 private NewDialpadFragment mDialpadFragment;
130
131 /**
132 * Fragment for searching phone numbers using the alphanumeric keyboard.
133 */
134 private NewSearchFragment mRegularSearchFragment;
135
136 /**
137 * Fragment for searching phone numbers using the dialpad.
138 */
139 private SmartDialSearchFragment mSmartDialSearchFragment;
140
141 private View mMenuButton;
142 private View mCallHistoryButton;
143 private View mDialpadButton;
144
145 // Padding view used to shift the fragments up when the dialpad is shown.
146 private View mBottomPaddingView;
147
Yorke Lee6b049122013-07-16 10:38:02 -0700148 /**
149 * True when this Activity is in its search UI (with a {@link SearchView} and
150 * {@link PhoneNumberPickerFragment}).
151 */
152 private boolean mInSearchUi;
Yorke Leed9999322013-07-19 09:22:03 -0700153 private View mSearchViewContainer;
154 private View mSearchViewCloseButton;
155 private EditText mSearchView;
Yorke Lee6b049122013-07-16 10:38:02 -0700156
Yorke Lee6b049122013-07-16 10:38:02 -0700157 /**
158 * The index of the Fragment (or, the tab) that has last been manually selected.
159 * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call)
160 */
161 private int mLastManuallySelectedFragment;
162
Yorke Lee6b049122013-07-16 10:38:02 -0700163 /**
164 * Listener used when one of phone numbers in search UI is selected. This will initiate a
165 * phone call using the phone number.
166 */
167 private final OnPhoneNumberPickerActionListener mPhoneNumberPickerActionListener =
168 new OnPhoneNumberPickerActionListener() {
169 @Override
170 public void onPickPhoneNumberAction(Uri dataUri) {
171 // Specify call-origin so that users will see the previous tab instead of
172 // CallLog screen (search UI will be automatically exited).
173 PhoneNumberInteraction.startInteractionForPhoneCall(
Yorke Leedfb2eee2013-06-26 18:24:32 -0700174 NewDialtactsActivity.this, dataUri, getCallOrigin());
Yorke Lee6b049122013-07-16 10:38:02 -0700175 }
176
177 @Override
178 public void onShortcutIntentCreated(Intent intent) {
179 Log.w(TAG, "Unsupported intent has come (" + intent + "). Ignoring.");
180 }
181
182 @Override
183 public void onHomeInActionBarSelected() {
184 exitSearchUi();
185 }
186 };
187
188 /**
189 * Listener used to send search queries to the phone search fragment.
190 */
Yorke Leed9999322013-07-19 09:22:03 -0700191 private final TextWatcher mPhoneSearchQueryTextListener = new TextWatcher() {
192 @Override
193 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
194 }
195
196 @Override
197 public void onTextChanged(CharSequence s, int start, int before, int count) {
198 final boolean smartDialSearch = isDialpadShowing();
199 final String newText = s.toString();
200 // Show search result with non-empty text. Show a bare list otherwise.
201 if (TextUtils.isEmpty(newText) && mInSearchUi) {
202 exitSearchUi();
203 mSearchViewCloseButton.setVisibility(View.GONE);
204 return;
205 } else if (!TextUtils.isEmpty(newText) && !mInSearchUi) {
206 enterSearchUi(smartDialSearch);
Yorke Lee6b049122013-07-16 10:38:02 -0700207 }
208
Yorke Leed9999322013-07-19 09:22:03 -0700209 if (isDialpadShowing()) {
210 mSmartDialSearchFragment.setQueryString(newText, false);
211 } else {
212 mRegularSearchFragment.setQueryString(newText, false);
Yorke Lee6b049122013-07-16 10:38:02 -0700213 }
Yorke Leed9999322013-07-19 09:22:03 -0700214 mSearchViewCloseButton.setVisibility(View.VISIBLE);
215 return;
216 }
217
218 @Override
219 public void afterTextChanged(Editable s) {
220 }
Yorke Lee6b049122013-07-16 10:38:02 -0700221 };
222
Yorke Leedfb2eee2013-06-26 18:24:32 -0700223 private boolean isDialpadShowing() {
224 return mDialpadFragment.isVisible();
225 }
226
Yorke Lee6b049122013-07-16 10:38:02 -0700227 @Override
Yorke Leedfb2eee2013-06-26 18:24:32 -0700228 protected void onCreate(Bundle savedInstanceState) {
229 super.onCreate(savedInstanceState);
Yorke Lee6b049122013-07-16 10:38:02 -0700230
231 final Intent intent = getIntent();
232 fixIntent(intent);
233
Yorke Leedfb2eee2013-06-26 18:24:32 -0700234 setContentView(R.layout.new_dialtacts_activity);
Yorke Lee6b049122013-07-16 10:38:02 -0700235
Yorke Leedfb2eee2013-06-26 18:24:32 -0700236 getActionBar().hide();
Yorke Lee6b049122013-07-16 10:38:02 -0700237
Yorke Leedfb2eee2013-06-26 18:24:32 -0700238 mPhoneFavoriteFragment = new NewPhoneFavoriteFragment();
239 mPhoneFavoriteFragment.setListener(mPhoneFavoriteListener);
Yorke Lee6b049122013-07-16 10:38:02 -0700240
Yorke Leedfb2eee2013-06-26 18:24:32 -0700241 mRegularSearchFragment = new NewSearchFragment();
242 mSmartDialSearchFragment = new SmartDialSearchFragment();
243 mDialpadFragment = new NewDialpadFragment();
Yorke Lee6b049122013-07-16 10:38:02 -0700244
Yorke Leedfb2eee2013-06-26 18:24:32 -0700245 // TODO krelease: load fragments on demand instead of creating all of them at run time
246 final FragmentTransaction ft = getFragmentManager().beginTransaction();
247 ft.add(R.id.dialtacts_frame, mPhoneFavoriteFragment, TAG_FAVORITES_FRAGMENT);
248 ft.add(R.id.dialtacts_frame, mRegularSearchFragment, TAG_REGULAR_SEARCH_FRAGMENT);
249 ft.add(R.id.dialtacts_frame, mSmartDialSearchFragment, TAG_SMARTDIAL_SEARCH_FRAGMENT);
250 ft.add(R.id.dialtacts_container, mDialpadFragment, TAG_DIALPAD_FRAGMENT);
251 ft.hide(mRegularSearchFragment);
252 ft.hide(mDialpadFragment);
253 ft.hide(mSmartDialSearchFragment);
254 ft.commit();
Yorke Lee6b049122013-07-16 10:38:02 -0700255
Yorke Leedfb2eee2013-06-26 18:24:32 -0700256 mBottomPaddingView = findViewById(R.id.dialtacts_bottom_padding);
257 prepareSearchView();
Yorke Lee6b049122013-07-16 10:38:02 -0700258
259 // Load the last manually loaded tab
260 mPrefs = this.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
Yorke Lee6b049122013-07-16 10:38:02 -0700261
Yorke Leedfb2eee2013-06-26 18:24:32 -0700262 /*
263 * TODO krelease : Remember which fragment was last displayed, and then redisplay it as
264 * necessary. mLastManuallySelectedFragment = mPrefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB,
265 * PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT); if (mLastManuallySelectedFragment >=
266 * TAB_INDEX_COUNT) { // Stored value may have exceeded the number of current tabs. Reset
267 * it. mLastManuallySelectedFragment = PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT; }
268 */
Yorke Lee6b049122013-07-16 10:38:02 -0700269
270 if (UI.FILTER_CONTACTS_ACTION.equals(intent.getAction())
Yorke Leedfb2eee2013-06-26 18:24:32 -0700271 && savedInstanceState == null) {
Yorke Lee6b049122013-07-16 10:38:02 -0700272 setupFilterText(intent);
273 }
274 }
275
276 @Override
Yorke Leedfb2eee2013-06-26 18:24:32 -0700277 protected void onResume() {
278 super.onResume();
279 final FragmentManager fm = getFragmentManager();
280 mPhoneFavoriteFragment = (NewPhoneFavoriteFragment) fm.findFragmentByTag(
281 TAG_FAVORITES_FRAGMENT);
282 mDialpadFragment = (NewDialpadFragment) fm.findFragmentByTag(TAG_DIALPAD_FRAGMENT);
283
284 mRegularSearchFragment = (NewSearchFragment) fm.findFragmentByTag(
285 TAG_REGULAR_SEARCH_FRAGMENT);
286 mRegularSearchFragment.setOnPhoneNumberPickerActionListener(
287 mPhoneNumberPickerActionListener);
288 if (!mRegularSearchFragment.isHidden()) {
289 final FragmentTransaction transaction = getFragmentManager().beginTransaction();
290 transaction.hide(mRegularSearchFragment);
291 transaction.commit();
Yorke Lee6b049122013-07-16 10:38:02 -0700292 }
293
Yorke Leedfb2eee2013-06-26 18:24:32 -0700294 mSmartDialSearchFragment = (SmartDialSearchFragment) fm.findFragmentByTag(
295 TAG_SMARTDIAL_SEARCH_FRAGMENT);
296 mSmartDialSearchFragment.setOnPhoneNumberPickerActionListener(
297 mPhoneNumberPickerActionListener);
298 if (!mSmartDialSearchFragment.isHidden()) {
299 final FragmentTransaction transaction = getFragmentManager().beginTransaction();
300 transaction.hide(mSmartDialSearchFragment);
301 transaction.commit();
Yorke Lee6b049122013-07-16 10:38:02 -0700302 }
303 }
304
305 @Override
Yorke Leedfb2eee2013-06-26 18:24:32 -0700306 public boolean onMenuItemClick(MenuItem item) {
307 switch (item.getItemId()) {
308 case R.id.menu_import_export:
309 // We hard-code the "contactsAreAvailable" argument because doing it properly would
310 // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
311 // now in Dialtacts for (potential) performance reasons. Compare with how it is
312 // done in {@link PeopleActivity}.
313 ImportExportDialogFragment.show(getFragmentManager(), true,
314 DialtactsActivity.class);
315 return true;
316 case R.id.menu_clear_frequents:
317 ClearFrequentsDialog.show(getFragmentManager());
318 return true;
319 case R.id.add_contact:
320 try {
321 startActivity(new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI));
322 } catch (ActivityNotFoundException e) {
323 Toast toast = Toast.makeText(this, R.string.add_contact_not_available,
324 Toast.LENGTH_SHORT);
325 toast.show();
326 }
327 return true;
328 case R.id.menu_call_settings:
329 final Intent settingsIntent = DialtactsActivity.getCallSettingsIntent();
330 startActivity(settingsIntent);
331 }
332 return false;
Yorke Lee6b049122013-07-16 10:38:02 -0700333 }
334
335 @Override
336 public void onClick(View view) {
337 switch (view.getId()) {
Yorke Lee6b049122013-07-16 10:38:02 -0700338 case R.id.overflow_menu: {
Yorke Leedfb2eee2013-06-26 18:24:32 -0700339 final PopupMenu popupMenu = new PopupMenu(NewDialtactsActivity.this, view);
340 final Menu menu = popupMenu.getMenu();
341 popupMenu.inflate(R.menu.dialtacts_options_new);
342 popupMenu.setOnMenuItemClickListener(this);
343 popupMenu.show();
Yorke Lee6b049122013-07-16 10:38:02 -0700344 break;
345 }
Yorke Leedfb2eee2013-06-26 18:24:32 -0700346 case R.id.dialpad_button:
347 showDialpadFragment();
348 break;
349 case R.id.call_history_button:
350 final Intent intent = new Intent(this, NewCallLogActivity.class);
351 startActivity(intent);
352 break;
Yorke Leed9999322013-07-19 09:22:03 -0700353 case R.id.search_close_button:
354 // Clear the search field
355 if (!TextUtils.isEmpty(mSearchView.getText())) {
356 mSearchView.setText("");
357 }
358 break;
Yorke Lee6b049122013-07-16 10:38:02 -0700359 default: {
360 Log.wtf(TAG, "Unexpected onClick event from " + view);
361 break;
362 }
363 }
364 }
365
Yorke Leedfb2eee2013-06-26 18:24:32 -0700366 private void showDialpadFragment() {
Yorke Lee6b049122013-07-16 10:38:02 -0700367 final FragmentTransaction ft = getFragmentManager().beginTransaction();
Yorke Leedfb2eee2013-06-26 18:24:32 -0700368 ft.setCustomAnimations(R.anim.slide_in, 0);
369 ft.show(mDialpadFragment);
370 ft.commit();
371 }
Yorke Lee6b049122013-07-16 10:38:02 -0700372
Yorke Leedfb2eee2013-06-26 18:24:32 -0700373 private void hideDialpadFragment() {
374 final FragmentTransaction ft = getFragmentManager().beginTransaction();
375 ft.setCustomAnimations(0, R.anim.slide_out);
376 ft.hide(mDialpadFragment);
377 ft.commit();
Yorke Lee6b049122013-07-16 10:38:02 -0700378 }
379
380 private void prepareSearchView() {
Yorke Leed9999322013-07-19 09:22:03 -0700381 mSearchViewContainer = findViewById(R.id.search_view_container);
382 mSearchViewCloseButton = findViewById(R.id.search_close_button);
383 mSearchViewCloseButton.setClickable(true);
384 mSearchViewCloseButton.setOnClickListener(this);
385 mSearchView = (EditText) findViewById(R.id.search_view);
386 mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener);
387 mSearchView.setHint(getString(R.string.dialer_hint_find_contact));
388 mSearchView.setOnFocusChangeListener(new OnFocusChangeListener() {
Yorke Lee6b049122013-07-16 10:38:02 -0700389 @Override
390 public void onFocusChange(View view, boolean hasFocus) {
391 if (hasFocus) {
392 showInputMethod(view.findFocus());
393 }
394 }
395 });
Yorke Lee6b049122013-07-16 10:38:02 -0700396 }
397
Yorke Leedfb2eee2013-06-26 18:24:32 -0700398 private void hideDialpadFragmentIfNecessary() {
399 if (mDialpadFragment.isVisible()) {
400 hideDialpadFragment();
401 }
402 }
Yorke Lee6b049122013-07-16 10:38:02 -0700403
Yorke Leedfb2eee2013-06-26 18:24:32 -0700404 final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
405 @Override
406 public void onAnimationEnd(Animator animation) {
Yorke Leed9999322013-07-19 09:22:03 -0700407 mSearchViewContainer.setVisibility(View.GONE);
Yorke Leedfb2eee2013-06-26 18:24:32 -0700408 }
409 };
410
411 public void hideSearchBar() {
Yorke Leed9999322013-07-19 09:22:03 -0700412 mSearchViewContainer.animate().cancel();
413 mSearchViewContainer.setAlpha(1);
414 mSearchViewContainer.setTranslationY(0);
415 mSearchViewContainer.animate().withLayer().alpha(0).translationY(-mSearchView.getHeight())
416 .setDuration(200).setListener(mHideListener);
Yorke Leedfb2eee2013-06-26 18:24:32 -0700417
418 mPhoneFavoriteFragment.getView().animate().withLayer()
Yorke Leed9999322013-07-19 09:22:03 -0700419 .translationY(-mSearchViewContainer.getHeight()).setDuration(200).setListener(
Yorke Leedfb2eee2013-06-26 18:24:32 -0700420 new AnimatorListenerAdapter() {
421 @Override
422 public void onAnimationEnd(Animator animation) {
423 mBottomPaddingView.setVisibility(View.VISIBLE);
424 mPhoneFavoriteFragment.getView().setTranslationY(0);
425 }
426 });
427 }
428
429 public void showSearchBar() {
Yorke Leed9999322013-07-19 09:22:03 -0700430 mSearchViewContainer.animate().cancel();
431 mSearchViewContainer.setAlpha(0);
432 mSearchViewContainer.setTranslationY(-mSearchViewContainer.getHeight());
433 mSearchViewContainer.animate().withLayer().alpha(1).translationY(0).setDuration(200)
Yorke Leedfb2eee2013-06-26 18:24:32 -0700434 .setListener(new AnimatorListenerAdapter() {
435 @Override
436 public void onAnimationStart(Animator animation) {
Yorke Leed9999322013-07-19 09:22:03 -0700437 mSearchViewContainer.setVisibility(View.VISIBLE);
Yorke Leedfb2eee2013-06-26 18:24:32 -0700438 }
439 });
440
Yorke Leed9999322013-07-19 09:22:03 -0700441 mPhoneFavoriteFragment.getView().setTranslationY(-mSearchViewContainer.getHeight());
Yorke Leedfb2eee2013-06-26 18:24:32 -0700442 mPhoneFavoriteFragment.getView().animate().withLayer().translationY(0).setDuration(200)
443 .setListener(
444 new AnimatorListenerAdapter() {
445 @Override
446 public void onAnimationStart(Animator animation) {
447 mBottomPaddingView.setVisibility(View.GONE);
448 }
449 });
450 }
451
452
453 public void setupFakeActionBarItems() {
454 mMenuButton = findViewById(R.id.overflow_menu);
455 if (mMenuButton != null) {
456 // mMenuButton.setMinimumWidth(fakeMenuItemWidth);
457 if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
458 // This is required for dialpad button's layout, so must not use GONE here.
459 mMenuButton.setVisibility(View.INVISIBLE);
460 } else {
461 mMenuButton.setOnClickListener(this);
Yorke Lee6b049122013-07-16 10:38:02 -0700462 }
463 }
Yorke Leedfb2eee2013-06-26 18:24:32 -0700464
465 mCallHistoryButton = findViewById(R.id.call_history_button);
466 // mCallHistoryButton.setMinimumWidth(fakeMenuItemWidth);
467 mCallHistoryButton.setOnClickListener(this);
468
469 mDialpadButton = findViewById(R.id.dialpad_button);
470 // DialpadButton.setMinimumWidth(fakeMenuItemWidth);
471 mDialpadButton.setOnClickListener(this);
Yorke Lee6b049122013-07-16 10:38:02 -0700472 }
473
474 @Override
475 protected void onPause() {
476 super.onPause();
Yorke Lee6b049122013-07-16 10:38:02 -0700477 mPrefs.edit().putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedFragment)
478 .apply();
479 requestBackup();
480 }
481
482 private void requestBackup() {
483 final BackupManager bm = new BackupManager(this);
484 bm.dataChanged();
485 }
486
487 private void fixIntent(Intent intent) {
488 // This should be cleaned up: the call key used to send an Intent
489 // that just said to go to the recent calls list. It now sends this
490 // abstract action, but this class hasn't been rewritten to deal with it.
491 if (Intent.ACTION_CALL_BUTTON.equals(intent.getAction())) {
492 intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE);
493 intent.putExtra("call_key", true);
494 setIntent(intent);
495 }
496 }
497
Yorke Lee6b049122013-07-16 10:38:02 -0700498 /**
499 * Returns true if the intent is due to hitting the green send key (hardware call button:
500 * KEYCODE_CALL) while in a call.
501 *
502 * @param intent the intent that launched this activity
503 * @param recentCallsRequest true if the intent is requesting to view recent calls
504 * @return true if the intent is due to hitting the green send key while in a call
505 */
Yorke Leedfb2eee2013-06-26 18:24:32 -0700506 private boolean isSendKeyWhileInCall(Intent intent, boolean recentCallsRequest) {
Yorke Lee6b049122013-07-16 10:38:02 -0700507 // If there is a call in progress go to the call screen
508 if (recentCallsRequest) {
509 final boolean callKey = intent.getBooleanExtra("call_key", false);
510
511 try {
512 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
513 if (callKey && phone != null && phone.showCallScreen()) {
514 return true;
515 }
516 } catch (RemoteException e) {
517 Log.e(TAG, "Failed to handle send while in call", e);
518 }
519 }
520
521 return false;
522 }
523
524 /**
525 * Sets the current tab based on the intent's request type
526 *
527 * @param intent Intent that contains information about which tab should be selected
528 */
Yorke Leedfb2eee2013-06-26 18:24:32 -0700529 private void displayFragment(Intent intent) {
530 // TODO krelease: Make navigation via intent work by displaying the correct fragment
531 // as appropriate.
532
Yorke Lee6b049122013-07-16 10:38:02 -0700533 // If we got here by hitting send and we're in call forward along to the in-call activity
534 boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.resolveType(
535 getContentResolver()));
536 if (isSendKeyWhileInCall(intent, recentCallsRequest)) {
537 finish();
538 return;
539 }
Yorke Lee6b049122013-07-16 10:38:02 -0700540 }
541
542 @Override
543 public void onNewIntent(Intent newIntent) {
544 setIntent(newIntent);
545 fixIntent(newIntent);
Yorke Leedfb2eee2013-06-26 18:24:32 -0700546 displayFragment(newIntent);
Yorke Lee6b049122013-07-16 10:38:02 -0700547 final String action = newIntent.getAction();
548 if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
549 setupFilterText(newIntent);
550 }
Yorke Leedfb2eee2013-06-26 18:24:32 -0700551 if (mInSearchUi || (mRegularSearchFragment != null && mRegularSearchFragment.isVisible())) {
Yorke Lee6b049122013-07-16 10:38:02 -0700552 exitSearchUi();
553 }
554
Yorke Leedfb2eee2013-06-26 18:24:32 -0700555 // TODO krelease: Handle onNewIntent for all other fragments
556 /*
557 *if (mViewPager.getCurrentItem() == TAB_INDEX_DIALER) { if (mDialpadFragment != null) {
558 * mDialpadFragment.setStartedFromNewIntent(true); } else { Log.e(TAG,
559 * "DialpadFragment isn't ready yet when the tab is already selected."); } } else if
560 * (mViewPager.getCurrentItem() == TAB_INDEX_CALL_LOG) { if (mCallLogFragment != null) {
561 * mCallLogFragment.configureScreenFromIntent(newIntent); } else { Log.e(TAG,
562 * "CallLogFragment isn't ready yet when the tab is already selected."); } }
563 */
Yorke Lee6b049122013-07-16 10:38:02 -0700564 invalidateOptionsMenu();
565 }
566
567 /** Returns true if the given intent contains a phone number to populate the dialer with */
568 private boolean isDialIntent(Intent intent) {
569 final String action = intent.getAction();
570 if (Intent.ACTION_DIAL.equals(action) || ACTION_TOUCH_DIALER.equals(action)) {
571 return true;
572 }
573 if (Intent.ACTION_VIEW.equals(action)) {
574 final Uri data = intent.getData();
575 if (data != null && CallUtil.SCHEME_TEL.equals(data.getScheme())) {
576 return true;
577 }
578 }
579 return false;
580 }
581
582 /**
583 * Returns an appropriate call origin for this Activity. May return null when no call origin
584 * should be used (e.g. when some 3rd party application launched the screen. Call origin is
585 * for remembering the tab in which the user made a phone call, so the external app's DIAL
586 * request should not be counted.)
587 */
588 public String getCallOrigin() {
589 return !isDialIntent(getIntent()) ? CALL_ORIGIN_DIALTACTS : null;
590 }
591
592 /**
593 * Retrieves the filter text stored in {@link #setupFilterText(Intent)}.
594 * This text originally came from a FILTER_CONTACTS_ACTION intent received
595 * by this activity. The stored text will then be cleared after after this
596 * method returns.
597 *
598 * @return The stored filter text
599 */
600 public String getAndClearFilterText() {
601 String filterText = mFilterText;
602 mFilterText = null;
603 return filterText;
604 }
605
606 /**
607 * Stores the filter text associated with a FILTER_CONTACTS_ACTION intent.
608 * This is so child activities can check if they are supposed to display a filter.
609 *
610 * @param intent The intent received in {@link #onNewIntent(Intent)}
611 */
612 private void setupFilterText(Intent intent) {
613 // If the intent was relaunched from history, don't apply the filter text.
614 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
615 return;
616 }
617 String filter = intent.getStringExtra(UI.FILTER_TEXT_EXTRA_KEY);
618 if (filter != null && filter.length() > 0) {
619 mFilterText = filter;
620 }
621 }
622
Yorke Leedfb2eee2013-06-26 18:24:32 -0700623 private final NewPhoneFavoriteFragment.Listener mPhoneFavoriteListener =
624 new NewPhoneFavoriteFragment.Listener() {
Yorke Lee6b049122013-07-16 10:38:02 -0700625 @Override
626 public void onContactSelected(Uri contactUri) {
627 PhoneNumberInteraction.startInteractionForPhoneCall(
Yorke Leedfb2eee2013-06-26 18:24:32 -0700628 NewDialtactsActivity.this, contactUri, getCallOrigin());
Yorke Lee6b049122013-07-16 10:38:02 -0700629 }
630
631 @Override
632 public void onCallNumberDirectly(String phoneNumber) {
633 Intent intent = CallUtil.getCallIntent(phoneNumber, getCallOrigin());
634 startActivity(intent);
635 }
636 };
637
Yorke Leedfb2eee2013-06-26 18:24:32 -0700638 /* TODO krelease: This is only relevant for phones that have a hard button search key (i.e.
639 * Nexus S). Supporting it is a little more tricky because of the dialpad fragment might
640 * be showing when the search key is pressed so there is more state management involved.
Yorke Lee6b049122013-07-16 10:38:02 -0700641
642 @Override
643 public void startSearch(String initialQuery, boolean selectInitialQuery,
644 Bundle appSearchData, boolean globalSearch) {
Yorke Leedfb2eee2013-06-26 18:24:32 -0700645 if (mRegularSearchFragment != null && mRegularSearchFragment.isAdded() && !globalSearch) {
Yorke Lee6b049122013-07-16 10:38:02 -0700646 if (mInSearchUi) {
647 if (mSearchView.hasFocus()) {
648 showInputMethod(mSearchView.findFocus());
649 } else {
650 mSearchView.requestFocus();
651 }
652 } else {
653 enterSearchUi();
654 }
655 } else {
656 super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
657 }
Yorke Leedfb2eee2013-06-26 18:24:32 -0700658 }*/
Yorke Lee6b049122013-07-16 10:38:02 -0700659
660 private void showInputMethod(View view) {
Yorke Leedfb2eee2013-06-26 18:24:32 -0700661 final InputMethodManager imm = (InputMethodManager) getSystemService(
662 Context.INPUT_METHOD_SERVICE);
Yorke Lee6b049122013-07-16 10:38:02 -0700663 if (imm != null) {
Yorke Leedfb2eee2013-06-26 18:24:32 -0700664 imm.showSoftInput(view, 0);
Yorke Lee6b049122013-07-16 10:38:02 -0700665 }
666 }
667
668 private void hideInputMethod(View view) {
Yorke Leedfb2eee2013-06-26 18:24:32 -0700669 final InputMethodManager imm = (InputMethodManager) getSystemService(
670 Context.INPUT_METHOD_SERVICE);
Yorke Lee6b049122013-07-16 10:38:02 -0700671 if (imm != null && view != null) {
672 imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
673 }
674 }
675
676 /**
Yorke Leedfb2eee2013-06-26 18:24:32 -0700677 * Shows the search fragment
Yorke Lee6b049122013-07-16 10:38:02 -0700678 */
Yorke Leedfb2eee2013-06-26 18:24:32 -0700679 private void enterSearchUi(boolean smartDialSearch) {
680 final FragmentTransaction transaction = getFragmentManager().beginTransaction();
681 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
682 transaction.hide(mPhoneFavoriteFragment);
683 if (smartDialSearch) {
684 transaction.show(mSmartDialSearchFragment);
685 } else {
686 transaction.show(mRegularSearchFragment);
Yorke Lee6b049122013-07-16 10:38:02 -0700687 }
Yorke Leedfb2eee2013-06-26 18:24:32 -0700688 transaction.commit();
Yorke Lee6b049122013-07-16 10:38:02 -0700689
Yorke Leedfb2eee2013-06-26 18:24:32 -0700690 mInSearchUi = true;
Yorke Lee6b049122013-07-16 10:38:02 -0700691 }
692
693 /**
Yorke Leedfb2eee2013-06-26 18:24:32 -0700694 * Hides the search fragment
Yorke Lee6b049122013-07-16 10:38:02 -0700695 */
Yorke Leedfb2eee2013-06-26 18:24:32 -0700696 private void exitSearchUi() {
697 final FragmentTransaction transaction = getFragmentManager().beginTransaction();
698 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
699 transaction.hide(mRegularSearchFragment);
700 transaction.hide(mSmartDialSearchFragment);
701 transaction.show(mPhoneFavoriteFragment);
702 transaction.commit();
703 mInSearchUi = false;
Yorke Lee6b049122013-07-16 10:38:02 -0700704 }
705
706 /** Returns an Intent to launch Call Settings screen */
707 public static Intent getCallSettingsIntent() {
708 final Intent intent = new Intent(Intent.ACTION_MAIN);
709 intent.setClassName(PHONE_PACKAGE, CALL_SETTINGS_CLASS_NAME);
710 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
711 return intent;
712 }
713
714 @Override
Yorke Leedfb2eee2013-06-26 18:24:32 -0700715 public void onBackPressed() {
716 if (mDialpadFragment.isVisible()) {
717 hideDialpadFragment();
718 } else if (mInSearchUi) {
Yorke Leed9999322013-07-19 09:22:03 -0700719 mSearchView.setText(null);
Yorke Leedfb2eee2013-06-26 18:24:32 -0700720 } else if (isTaskRoot()) {
721 // Instead of stopping, simply push this to the back of the stack.
722 // This is only done when running at the top of the stack;
723 // otherwise, we have been launched by someone else so need to
724 // allow the user to go back to the caller.
725 moveTaskToBack(false);
726 } else {
727 super.onBackPressed();
Yorke Lee6b049122013-07-16 10:38:02 -0700728 }
Yorke Leedfb2eee2013-06-26 18:24:32 -0700729 }
730
731 @Override
732 public void onDialpadQueryChanged(String query) {
733 final String normalizedQuery = SmartDialNameMatcher.normalizeNumber(query,
734 SmartDialNameMatcher.LATIN_SMART_DIAL_MAP);
Yorke Leed9999322013-07-19 09:22:03 -0700735 if (!TextUtils.equals(mSearchView.getText(), normalizedQuery)) {
736 mSearchView.setText(normalizedQuery);
Yorke Lee6b049122013-07-16 10:38:02 -0700737 }
738 }
Yorke Leedfb2eee2013-06-26 18:24:32 -0700739
740 @Override
741 public void onListFragmentScrollStateChange(int scrollState) {
742 if (scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
743 hideDialpadFragmentIfNecessary();
744 hideInputMethod(getCurrentFocus());
745 }
746 }
747
748 @Override
749 public void onPhoneFavoriteFragmentStarted() {
750 setupFakeActionBarItems();
751 }
Yorke Lee6b049122013-07-16 10:38:02 -0700752}