summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Chen <ajchen@google.com>2017-04-26 17:18:50 -0700
committerAnthony Chen <ajchen@google.com>2017-05-11 15:31:13 -0700
commit17d5ac7d0b429687765e940279726623f5f5f823 (patch)
tree7fac2a84a191fa7e7dfb9d6b316718274fa268cc
parent676781bf09b69966f83ba99c1b7ee0c7d6ae00e4 (diff)
downloadDialer-17d5ac7d0b429687765e940279726623f5f5f823.tar.gz
Clean up Dialer code.oreo-dr1-dev
- Clean up the use of fragments. Create newInstance() methods that will set the appropriate variables via arguments. - Ensure that TelecomActivity does not hold onto Fragment instances as this could lead to wrong lifecycle events being triggered. - Restructure OngoingCallFragment so that methods are more concise - Switch to using onStop/onStart in TelecomActivity to handle multi-window. - Remove the usage of commitAllowingStateLoss. Use commitNow/commit where appropriate. - Properly hook up the tone sounds for dialing - Remove unused code Test: connected phone via bluetooth, made some calls, dialed number, ensure no crashes Change-Id: Ib70367a970b09abb1fcb2621f03f940c31e92468
-rw-r--r--src/com/android/car/dialer/ContactDetailsFragment.java23
-rw-r--r--src/com/android/car/dialer/DialerFragment.java145
-rw-r--r--src/com/android/car/dialer/DialpadButton.java2
-rw-r--r--src/com/android/car/dialer/NoHfpFragment.java49
-rw-r--r--src/com/android/car/dialer/OngoingCallFragment.java399
-rw-r--r--src/com/android/car/dialer/StrequentsAdapter.java15
-rw-r--r--src/com/android/car/dialer/StrequentsFragment.java17
-rw-r--r--src/com/android/car/dialer/TelecomActivity.java235
8 files changed, 469 insertions, 416 deletions
diff --git a/src/com/android/car/dialer/ContactDetailsFragment.java b/src/com/android/car/dialer/ContactDetailsFragment.java
index a334f722..9feb00fd 100644
--- a/src/com/android/car/dialer/ContactDetailsFragment.java
+++ b/src/com/android/car/dialer/ContactDetailsFragment.java
@@ -48,8 +48,8 @@ import java.util.List;
public class ContactDetailsFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String TAG = "ContactDetailsFragment";
- private static final int DETAILS_QUERY_ID = 31415;
- private static final int PHONE_QUERY_ID = 42;
+ private static final int DETAILS_LOADER_QUERY_ID = 1;
+ private static final int PHONE_LOADER_QUERY_ID = 2;
private static final String KEY_URI = "uri";
private static final String[] CONTACT_DETAILS_PROJECTION = {
@@ -64,10 +64,12 @@ public class ContactDetailsFragment extends Fragment
public static ContactDetailsFragment newInstance(Uri uri, UiCallManager callManager) {
ContactDetailsFragment fragment = new ContactDetailsFragment();
+ fragment.mCallManager = callManager;
+
Bundle args = new Bundle();
args.putParcelable(KEY_URI, uri);
fragment.setArguments(args);
- fragment.mCallManager = callManager;
+
return fragment;
}
@@ -82,7 +84,7 @@ public class ContactDetailsFragment extends Fragment
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
+ getLoaderManager().initLoader(DETAILS_LOADER_QUERY_ID, null, this);
}
@Override
@@ -91,7 +93,7 @@ public class ContactDetailsFragment extends Fragment
Log.d(TAG, "onCreateLoader id=" + id);
}
- if (id != DETAILS_QUERY_ID) {
+ if (id != DETAILS_LOADER_QUERY_ID) {
return null;
}
@@ -125,8 +127,6 @@ public class ContactDetailsFragment extends Fragment
public TextView text;
public ImageView rightIcon;
- private int mViewType;
-
public ContactDetailViewHolder(View v) {
super(v);
card = v.findViewById(R.id.card);
@@ -143,24 +143,17 @@ public class ContactDetailsFragment extends Fragment
private static final int ID_HEADER = 1;
private static final int ID_CONTENT = 2;
- private final List<ContactDetailViewHolder> mData = new ArrayList<>();
- private final Cursor mCursor;
-
private final String mContactName;
- private final String mContactPhotoUri;
private List<Pair<String, String>> mPhoneNumbers = new ArrayList<>();
public ContactDetailsAdapter(Cursor cursor) {
super();
- mCursor = cursor;
int idColIdx = cursor.getColumnIndex(ContactsContract.Contacts._ID);
String contactId = cursor.getString(idColIdx);
int nameColIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
mContactName = cursor.getString(nameColIdx);
- int photoColIdx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI);
- mContactPhotoUri = cursor.getString(photoColIdx);
int hasPhoneColIdx = cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
boolean hasPhoneNumber = Integer.parseInt(cursor.getString(hasPhoneColIdx)) > 0;
@@ -169,7 +162,7 @@ public class ContactDetailsFragment extends Fragment
}
// Fetch the phone number from the contacts db using another loader.
- getLoaderManager().initLoader(PHONE_QUERY_ID, null,
+ getLoaderManager().initLoader(PHONE_LOADER_QUERY_ID, null,
new LoaderManager.LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
diff --git a/src/com/android/car/dialer/DialerFragment.java b/src/com/android/car/dialer/DialerFragment.java
index bf3197a5..642bf198 100644
--- a/src/com/android/car/dialer/DialerFragment.java
+++ b/src/com/android/car/dialer/DialerFragment.java
@@ -19,16 +19,18 @@ import android.content.Context;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
-import android.os.Handler;
+import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+
import com.android.car.apps.common.FabDrawable;
import com.android.car.dialer.telecom.TelecomUtils;
import com.android.car.dialer.telecom.UiCallManager;
@@ -40,12 +42,14 @@ import com.android.car.dialer.telecom.UiCallManager.CallListener;
public class DialerFragment extends Fragment {
private static final String TAG = "Em.DialerFragment";
private static final String INPUT_ACTIVE_KEY = "INPUT_ACTIVE_KEY";
+ private static final String DIAL_NUMBER_KEY = "DIAL_NUMBER_KEY";
+
+ private static final int TONE_LENGTH_MS = 150;
private static final int TONE_RELATIVE_VOLUME = 80;
- private static final int ABANDON_AUDIO_FOCUS_DELAY_MS = 250;
private static final int MAX_DIAL_NUMBER = 20;
- private static final int NO_TONE = -1;
- private static final ArrayMap<Integer, Integer> mToneMap = new ArrayMap<>();
+ private static final SparseIntArray mToneMap = new SparseIntArray();
+ private static final SparseArray<String> mDialValueMap = new SparseArray<>();
static {
mToneMap.put(KeyEvent.KEYCODE_1, ToneGenerator.TONE_DTMF_1);
@@ -60,14 +64,25 @@ public class DialerFragment extends Fragment {
mToneMap.put(KeyEvent.KEYCODE_0, ToneGenerator.TONE_DTMF_0);
mToneMap.put(KeyEvent.KEYCODE_STAR, ToneGenerator.TONE_DTMF_S);
mToneMap.put(KeyEvent.KEYCODE_POUND, ToneGenerator.TONE_DTMF_P);
+
+ mDialValueMap.put(KeyEvent.KEYCODE_1, "1");
+ mDialValueMap.put(KeyEvent.KEYCODE_2, "2");
+ mDialValueMap.put(KeyEvent.KEYCODE_3, "3");
+ mDialValueMap.put(KeyEvent.KEYCODE_4, "4");
+ mDialValueMap.put(KeyEvent.KEYCODE_5, "5");
+ mDialValueMap.put(KeyEvent.KEYCODE_6, "6");
+ mDialValueMap.put(KeyEvent.KEYCODE_7, "7");
+ mDialValueMap.put(KeyEvent.KEYCODE_8, "8");
+ mDialValueMap.put(KeyEvent.KEYCODE_9, "9");
+ mDialValueMap.put(KeyEvent.KEYCODE_0, "0");
+ mDialValueMap.put(KeyEvent.KEYCODE_STAR, "*");
+ mDialValueMap.put(KeyEvent.KEYCODE_POUND, "#");
}
private Context mContext;
private UiCallManager mUiCallManager;
private final StringBuffer mNumber = new StringBuffer(MAX_DIAL_NUMBER);
- private AudioManager mAudioManager;
private ToneGenerator mToneGenerator;
- private final Handler mHandler = new Handler();
private final Object mToneGeneratorLock = new Object();
private TextView mNumberView;
private boolean mShowInput = true;
@@ -87,28 +102,36 @@ public class DialerFragment extends Fragment {
void onDialerBackClick();
}
- public static DialerFragment newInstance(UiCallManager callManager) {
+ /**
+ * Creates a new instance of the {@link DialerFragment} and display the given number as the one
+ * to dial.
+ */
+ static DialerFragment newInstance(UiCallManager callManager,
+ DialerBackButtonListener listener, @Nullable String dialNumber) {
DialerFragment fragment = new DialerFragment();
fragment.mUiCallManager = callManager;
- return fragment;
- }
+ fragment.mBackListener = listener;
- /**
- * Sets the given {@link DialerBackButtonListener} to be notified whenever the back button
- * on the dialer has been clicked. Passing {@code null} to this method will clear all listeners.
- */
- public void setDialerBackButtonListener(DialerBackButtonListener listener) {
- mBackListener = listener;
+ if (!TextUtils.isEmpty(dialNumber)) {
+ Bundle args = new Bundle();
+ args.putString(DIAL_NUMBER_KEY, dialNumber);
+ fragment.setArguments(args);
+ }
+
+ return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mAudioManager =
- (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
if (savedInstanceState != null && savedInstanceState.containsKey(INPUT_ACTIVE_KEY)) {
mShowInput = savedInstanceState.getBoolean(INPUT_ACTIVE_KEY);
}
+
+ Bundle args = getArguments();
+ if (args != null) {
+ setDialNumber(args.getString(DIAL_NUMBER_KEY));
+ }
}
@Override
@@ -125,7 +148,7 @@ public class DialerFragment extends Fragment {
Log.v(TAG, "onCreateView: inflated successfully");
}
- view.findViewById(R.id.exit_dialer_button).setOnClickListener((unusedView) -> {
+ view.findViewById(R.id.exit_dialer_button).setOnClickListener(v -> {
if (mBackListener != null) {
mBackListener.onDialerBackClick();
}
@@ -137,9 +160,10 @@ public class DialerFragment extends Fragment {
Log.v(TAG, "mShowInput: " + mShowInput);
}
- View callButton = view.findViewById(R.id.call);
FabDrawable answerCallDrawable = new FabDrawable(mContext);
- answerCallDrawable.setFabAndStrokeColor(getResources().getColor(R.color.phone_call));
+ answerCallDrawable.setFabAndStrokeColor(getContext().getColor(R.color.phone_call));
+
+ View callButton = view.findViewById(R.id.call);
callButton.setBackground(answerCallDrawable);
callButton.setVisibility(View.VISIBLE);
callButton.setOnClickListener((unusedView) -> {
@@ -151,16 +175,17 @@ public class DialerFragment extends Fragment {
mUiCallManager.safePlaceCall(mNumber.toString(), false);
}
});
+
View deleteButton = view.findViewById(R.id.delete);
deleteButton.setVisibility(View.VISIBLE);
- deleteButton.setOnClickListener((unusedView) -> {
+ deleteButton.setOnClickListener(v -> {
if (mNumber.length() != 0) {
mNumber.deleteCharAt(mNumber.length() - 1);
mNumberView.setText(getFormattedNumber(mNumber.toString()));
}
});
- setupKeypad(view);
+ setupKeypadClickListeners(view);
return view;
}
@@ -170,35 +195,47 @@ public class DialerFragment extends Fragment {
* associated value to {@link #mNumber}.
*/
private class DialpadClickListener implements View.OnClickListener {
- private String mValue;
+ private final int mTone;
+ private final String mValue;
- public DialpadClickListener(String value) {
- mValue = value;
+ DialpadClickListener(int keyCode) {
+ mTone = mToneMap.get(keyCode);
+ mValue = mDialValueMap.get(keyCode);
}
@Override
public void onClick(View v) {
mNumber.append(mValue);
mNumberView.setText(getFormattedNumber(mNumber.toString()));
+ playTone(mTone);
}
- };
+ }
- /**
- * Sets up the click listeners for all the dialpad buttons.
- */
- private void setupKeypad(View parent) {
- parent.findViewById(R.id.zero).setOnClickListener(new DialpadClickListener("0"));
- parent.findViewById(R.id.one).setOnClickListener(new DialpadClickListener("1"));
- parent.findViewById(R.id.two).setOnClickListener(new DialpadClickListener("2"));
- parent.findViewById(R.id.three).setOnClickListener(new DialpadClickListener("3"));
- parent.findViewById(R.id.four).setOnClickListener(new DialpadClickListener("4"));
- parent.findViewById(R.id.five).setOnClickListener(new DialpadClickListener("5"));
- parent.findViewById(R.id.six).setOnClickListener(new DialpadClickListener("6"));
- parent.findViewById(R.id.seven).setOnClickListener(new DialpadClickListener("7"));
- parent.findViewById(R.id.eight).setOnClickListener(new DialpadClickListener("8"));
- parent.findViewById(R.id.nine).setOnClickListener(new DialpadClickListener("9"));
- parent.findViewById(R.id.star).setOnClickListener(new DialpadClickListener("*"));
- parent.findViewById(R.id.pound).setOnClickListener(new DialpadClickListener("#"));
+ private void setupKeypadClickListeners(View parent) {
+ parent.findViewById(R.id.zero).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_0));
+ parent.findViewById(R.id.one).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_1));
+ parent.findViewById(R.id.two).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_2));
+ parent.findViewById(R.id.three).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_3));
+ parent.findViewById(R.id.four).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_4));
+ parent.findViewById(R.id.five).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_5));
+ parent.findViewById(R.id.six).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_6));
+ parent.findViewById(R.id.seven).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_7));
+ parent.findViewById(R.id.eight).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_8));
+ parent.findViewById(R.id.nine).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_9));
+ parent.findViewById(R.id.star).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_STAR));
+ parent.findViewById(R.id.pound).setOnClickListener(
+ new DialpadClickListener(KeyEvent.KEYCODE_POUND));
}
@Override
@@ -237,7 +274,7 @@ public class DialerFragment extends Fragment {
mNumberView = null;
}
- public void setDialNumber(final String number) {
+ private void setDialNumber(final String number) {
if (TextUtils.isEmpty(number)) {
return;
}
@@ -256,6 +293,18 @@ public class DialerFragment extends Fragment {
mNumberView.setText(getFormattedNumber(mNumber.toString()));
}
+ private void playTone(int tone) {
+ synchronized (mToneGeneratorLock) {
+ if (mToneGenerator == null) {
+ Log.w(TAG, "playTone: mToneGenerator == null, tone: " + tone);
+ return;
+ }
+
+ // Start the new tone (will stop any playing tone)
+ mToneGenerator.startTone(tone, TONE_LENGTH_MS);
+ }
+ }
+
private void stopTone() {
synchronized (mToneGeneratorLock) {
if (mToneGenerator == null) {
@@ -263,17 +312,9 @@ public class DialerFragment extends Fragment {
return;
}
mToneGenerator.stopTone();
- mHandler.postDelayed(mDelayedAbandonAudioFocusRunnable, ABANDON_AUDIO_FOCUS_DELAY_MS);
}
}
- private final Runnable mDelayedAbandonAudioFocusRunnable = new Runnable() {
- @Override
- public void run() {
- mAudioManager.abandonAudioFocus(null);
- }
- };
-
private String getFormattedNumber(String number) {
return TelecomUtils.getFormattedNumber(mContext, number);
}
diff --git a/src/com/android/car/dialer/DialpadButton.java b/src/com/android/car/dialer/DialpadButton.java
index 28926f59..7e058c0b 100644
--- a/src/com/android/car/dialer/DialpadButton.java
+++ b/src/com/android/car/dialer/DialpadButton.java
@@ -31,7 +31,7 @@ public class DialpadButton extends FrameLayout {
private String mNumberText;
private String mLetterText;
- private int mImageRes;
+ private int mImageRes = INVALID_IMAGE_RES;
public DialpadButton(Context context) {
super(context);
diff --git a/src/com/android/car/dialer/NoHfpFragment.java b/src/com/android/car/dialer/NoHfpFragment.java
index 16e736ae..295b4746 100644
--- a/src/com/android/car/dialer/NoHfpFragment.java
+++ b/src/com/android/car/dialer/NoHfpFragment.java
@@ -23,22 +23,63 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-
+/**
+ * A fragment that informs the user that there is no bluetooth device attached that can make
+ * phone calls.
+ */
public class NoHfpFragment extends Fragment {
+ private static final String ERROR_MESSAGE_KEY = "ERROR_MESSAGE_KEY";
+
+ private TextView mErrorMessageView;
private String mErrorMessage;
- public void setErrorMessage(String message) {
- mErrorMessage = message;
+ /**
+ * Returns an instance of the {@link NoHfpFragment} with the given error message as the one to
+ * display.
+ */
+ static NoHfpFragment newInstance(String errorMessage) {
+ NoHfpFragment fragment = new NoHfpFragment();
+
+ Bundle args = new Bundle();
+ args.putString(ERROR_MESSAGE_KEY, errorMessage);
+ fragment.setArguments(args);
+
+ return fragment;
+ }
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Bundle args = getArguments();
+ if (args != null) {
+ mErrorMessage = args.getString(ERROR_MESSAGE_KEY);
+ }
+ }
+
+ /**
+ * Sets the given error message to be displayed.
+ */
+ void setErrorMessage(String errorMessage) {
+ mErrorMessage = errorMessage;
+
+ // If this method is called before the error message view is available, then no need to
+ // set the message. Instead, it will be set in onCreateView().
+ if (mErrorMessageView != null && !TextUtils.isEmpty(mErrorMessage)) {
+ mErrorMessageView.setText(mErrorMessage);
+ }
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.no_hfp, container, false);
+ mErrorMessageView = v.findViewById(R.id.error_string);
+
// If no error message is set, the default string from the layout will be used.
if (!TextUtils.isEmpty(mErrorMessage)) {
- ((TextView) v.findViewById(R.id.error_string)).setText(mErrorMessage);
+ mErrorMessageView.setText(mErrorMessage);
}
+
return v;
}
}
diff --git a/src/com/android/car/dialer/OngoingCallFragment.java b/src/com/android/car/dialer/OngoingCallFragment.java
index 7e88f7be..87d4ebb0 100644
--- a/src/com/android/car/dialer/OngoingCallFragment.java
+++ b/src/com/android/car/dialer/OngoingCallFragment.java
@@ -27,20 +27,20 @@ import android.telecom.CallAudioState;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
+import android.util.SparseArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
-import android.view.animation.Interpolator;
import android.view.animation.Transformation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import com.android.car.apps.common.CircleBitmapDrawable;
import com.android.car.apps.common.FabDrawable;
import com.android.car.dialer.telecom.TelecomUtils;
@@ -49,12 +49,15 @@ import com.android.car.dialer.telecom.UiCallManager;
import com.android.car.dialer.telecom.UiCallManager.CallListener;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
+/**
+ * A fragment that displays information about an on-going call with options to hang up.
+ */
public class OngoingCallFragment extends Fragment {
- private static final String TAG = "Em.OngoingCall";
- private static final HashMap<Integer, Character> mDialpadButtonMap = new HashMap<>();
+ private static final String TAG = "OngoingCall";
+ private static final SparseArray<Character> mDialpadButtonMap = new SparseArray<>();
static {
mDialpadButtonMap.put(R.id.one, '1');
@@ -71,11 +74,10 @@ public class OngoingCallFragment extends Fragment {
mDialpadButtonMap.put(R.id.pound, '#');
}
- private UiCall mPrimaryCall;
- private UiCall mSecondaryCall;
+ private final Handler mHandler = new Handler();
+
private UiCall mLastRemovedCall;
private UiCallManager mUiCallManager;
- private Handler mHandler;
private View mRingingCallControls;
private View mActiveCallControls;
private ImageButton mEndCallButton;
@@ -95,17 +97,12 @@ public class OngoingCallFragment extends Fragment {
private View mDialpadContainer;
private View mSecondaryCallContainer;
private View mSecondaryCallControls;
- private List<View> mDialpadViews;
private String mLoadedNumber;
private CharSequence mCallInfoLabel;
private UiBluetoothMonitor mUiBluetoothMonitor;
- private final Interpolator
- mAccelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator();
- private final Interpolator mAccelerateInterpolator = new AccelerateInterpolator(10);
-
- public static OngoingCallFragment newInstance(
- UiCallManager callManager, UiBluetoothMonitor btMonitor) {
+ static OngoingCallFragment newInstance(UiCallManager callManager,
+ UiBluetoothMonitor btMonitor) {
OngoingCallFragment fragment = new OngoingCallFragment();
fragment.mUiCallManager = callManager;
fragment.mUiBluetoothMonitor = btMonitor;
@@ -115,7 +112,6 @@ public class OngoingCallFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mHandler = new Handler();
}
@Override
@@ -123,35 +119,17 @@ public class OngoingCallFragment extends Fragment {
super.onDestroy();
mHandler.removeCallbacks(mUpdateDurationRunnable);
mHandler.removeCallbacks(mStopDtmfToneRunnable);
- mHandler = null;
mLoadedNumber = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.ongoing_call, container, false);
- mRingingCallControls = view.findViewById(R.id.ringing_call_controls);
- mActiveCallControls = view.findViewById(R.id.active_call_controls);
- mEndCallButton = (ImageButton) view.findViewById(R.id.end_call);
- mUnholdCallButton = (ImageButton) view.findViewById(R.id.unhold_call);
- mMuteButton = (ImageButton) view.findViewById(R.id.mute);
- mToggleDialpadButton = (ImageButton) view.findViewById(R.id.toggle_dialpad);
- mDialpadContainer = view.findViewById(R.id.dialpad_container);
- mNameTextView = (TextView) view.findViewById(R.id.name);
- mSecondaryNameTextView = (TextView) view.findViewById(R.id.name_secondary);
- mStateTextView = (TextView) view.findViewById(R.id.info);
- mSecondaryStateTextView = (TextView) view.findViewById(R.id.info_secondary);
- mLargeContactPhotoView = (ImageView) view.findViewById(R.id.large_contact_photo);
- mSmallContactPhotoView = (ImageView) view.findViewById(R.id.small_contact_photo);
- mSecondaryCallContainer = view.findViewById(R.id.secondary_call_container);
- mSecondaryCallControls = view.findViewById(R.id.secondary_call_controls);
- mSwapButton = (ImageButton) view.findViewById(R.id.swap);
- mMergeButton = (ImageButton) view.findViewById(R.id.merge);
- mAnswerCallButton = (ImageButton) view.findViewById(R.id.answer_call_button);
- mRejectCallButton = (ImageButton) view.findViewById(R.id.reject_call_button);
-
- mDialpadViews = Arrays.asList(
+ initializeViews(view);
+ initializeClickListeners();
+
+ List<View> dialpadViews = Arrays.asList(
mDialpadContainer.findViewById(R.id.one),
mDialpadContainer.findViewById(R.id.two),
mDialpadContainer.findViewById(R.id.three),
@@ -163,16 +141,58 @@ public class OngoingCallFragment extends Fragment {
mDialpadContainer.findViewById(R.id.nine),
mDialpadContainer.findViewById(R.id.zero),
mDialpadContainer.findViewById(R.id.pound),
- mDialpadContainer.findViewById(R.id.star)
- );
+ mDialpadContainer.findViewById(R.id.star));
// In touch screen, we need to adjust the InCall card for the narrow screen to show the
// full dial pad.
- for (View dialpadView : mDialpadViews) {
+ for (View dialpadView : dialpadViews) {
dialpadView.setOnTouchListener(mDialpadTouchListener);
dialpadView.setOnKeyListener(mDialpadKeyListener);
}
+ mUiCallManager.addListener(mCallListener);
+
+ updateCalls();
+
+ return view;
+ }
+
+ private void initializeViews(View parent) {
+ mRingingCallControls = parent.findViewById(R.id.ringing_call_controls);
+ mActiveCallControls = parent.findViewById(R.id.active_call_controls);
+ mEndCallButton = parent.findViewById(R.id.end_call);
+ mUnholdCallButton = parent.findViewById(R.id.unhold_call);
+ mMuteButton = parent.findViewById(R.id.mute);
+ mToggleDialpadButton = parent.findViewById(R.id.toggle_dialpad);
+ mDialpadContainer = parent.findViewById(R.id.dialpad_container);
+ mNameTextView = parent.findViewById(R.id.name);
+ mSecondaryNameTextView = parent.findViewById(R.id.name_secondary);
+ mStateTextView = parent.findViewById(R.id.info);
+ mSecondaryStateTextView = parent.findViewById(R.id.info_secondary);
+ mLargeContactPhotoView = parent.findViewById(R.id.large_contact_photo);
+ mSmallContactPhotoView = parent.findViewById(R.id.small_contact_photo);
+ mSecondaryCallContainer = parent.findViewById(R.id.secondary_call_container);
+ mSecondaryCallControls = parent.findViewById(R.id.secondary_call_controls);
+ mSwapButton = parent.findViewById(R.id.swap);
+ mMergeButton = parent.findViewById(R.id.merge);
+ mAnswerCallButton = parent.findViewById(R.id.answer_call_button);
+ mRejectCallButton = parent.findViewById(R.id.reject_call_button);
+
+ Context context = getContext();
+ FabDrawable drawable = new FabDrawable(context);
+ drawable.setFabAndStrokeColor(context.getColor(R.color.phone_call));
+ mAnswerCallButton.setBackground(drawable);
+
+ drawable = new FabDrawable(context);
+ drawable.setFabAndStrokeColor(context.getColor(R.color.phone_end_call));
+ mEndCallButton.setBackground(drawable);
+
+ drawable = new FabDrawable(context);
+ drawable.setFabAndStrokeColor(context.getColor(R.color.phone_call));
+ mUnholdCallButton.setBackground(drawable);
+ }
+
+ private void initializeClickListeners() {
mAnswerCallButton.setOnClickListener((unusedView) -> {
UiCall call = mUiCallManager.getCallWithState(Call.STATE_RINGING);
if (call == null) {
@@ -181,10 +201,6 @@ public class OngoingCallFragment extends Fragment {
}
mUiCallManager.answerCall(call);
});
- Context context = getContext();
- FabDrawable answerCallDrawable = new FabDrawable(context);
- answerCallDrawable.setFabAndStrokeColor(getResources().getColor(R.color.phone_call));
- mAnswerCallButton.setBackground(answerCallDrawable);
mRejectCallButton.setOnClickListener((unusedView) -> {
UiCall call = mUiCallManager.getCallWithState(Call.STATE_RINGING);
@@ -203,9 +219,6 @@ public class OngoingCallFragment extends Fragment {
}
mUiCallManager.disconnectCall(call);
});
- FabDrawable endCallDrawable = new FabDrawable(context);
- endCallDrawable.setFabAndStrokeColor(getResources().getColor(R.color.phone_end_call));
- mEndCallButton.setBackground(endCallDrawable);
mUnholdCallButton.setOnClickListener((unusedView) -> {
UiCall call = mUiCallManager.getPrimaryCall();
@@ -215,17 +228,9 @@ public class OngoingCallFragment extends Fragment {
}
mUiCallManager.unholdCall(call);
});
- FabDrawable unholdCallDrawable = new FabDrawable(context);
- unholdCallDrawable.setFabAndStrokeColor(getResources().getColor(R.color.phone_call));
- mUnholdCallButton.setBackground(unholdCallDrawable);
- mMuteButton.setOnClickListener((unusedView) -> {
- if (mUiCallManager.getMuted()) {
- mUiCallManager.setMuted(false);
- } else {
- mUiCallManager.setMuted(true);
- }
- });
+ mMuteButton.setOnClickListener(
+ (unusedView) -> mUiCallManager.setMuted(!mUiCallManager.getMuted()));
mSwapButton.setOnClickListener((unusedView) -> {
UiCall call = mUiCallManager.getPrimaryCall();
@@ -242,13 +247,13 @@ public class OngoingCallFragment extends Fragment {
mMergeButton.setOnClickListener((unusedView) -> {
UiCall call = mUiCallManager.getPrimaryCall();
- UiCall secondarycall = mUiCallManager.getSecondaryCall();
- if (call == null || mSecondaryCall == null) {
+ UiCall secondaryCall = mUiCallManager.getSecondaryCall();
+ if (call == null || secondaryCall == null) {
Log.w(TAG, "There aren't two call to merge.");
return;
}
- mUiCallManager.conference(call, secondarycall);
+ mUiCallManager.conference(call, secondaryCall);
});
mToggleDialpadButton.setOnClickListener((unusedView) -> {
@@ -258,12 +263,6 @@ public class OngoingCallFragment extends Fragment {
openDialpad(true /*animate*/);
}
});
-
- mUiCallManager.addListener(mCallListener);
-
- updateCalls();
-
- return view;
}
@Override
@@ -278,24 +277,32 @@ public class OngoingCallFragment extends Fragment {
trySpeakerAudioRouteIfNecessary();
}
- private void rebindViews() {
+ private void updateCalls() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "updateCalls(); Primary call: " + mUiCallManager.getPrimaryCall()
+ + "; Secondary call:" + mUiCallManager.getSecondaryCall());
+ }
+
mHandler.removeCallbacks(mUpdateDurationRunnable);
- // Toggle the visibility between the active call controls, ringing call controls,
- // and no controls.
- CharSequence disconnectCauseLabel = mLastRemovedCall == null ?
- null : mLastRemovedCall.getDisconnectCause();
- if (mPrimaryCall == null && !TextUtils.isEmpty(disconnectCauseLabel)) {
+ UiCall primaryCall = mUiCallManager.getPrimaryCall();
+ CharSequence disconnectCauseLabel = mLastRemovedCall == null
+ ? null : mLastRemovedCall.getDisconnectCause();
+ if (primaryCall == null && !TextUtils.isEmpty(disconnectCauseLabel)) {
closeDialpad();
setStateText(disconnectCauseLabel);
return;
- } else if (mPrimaryCall == null || mPrimaryCall.getState() == Call.STATE_DISCONNECTED) {
+ }
+
+ if (primaryCall == null || primaryCall.getState() == Call.STATE_DISCONNECTED) {
closeDialpad();
setStateText(getString(R.string.call_state_call_ended));
mRingingCallControls.setVisibility(View.GONE);
mActiveCallControls.setVisibility(View.GONE);
return;
- } else if (mPrimaryCall.getState() == Call.STATE_RINGING) {
+ }
+
+ if (primaryCall.getState() == Call.STATE_RINGING) {
mRingingCallControls.setVisibility(View.VISIBLE);
mActiveCallControls.setVisibility(View.GONE);
} else {
@@ -303,85 +310,19 @@ public class OngoingCallFragment extends Fragment {
mActiveCallControls.setVisibility(View.VISIBLE);
}
- // Show the primary contact photo in the large ImageView on the right if there is no
- // secondary call. Otherwise, show it in the small ImageView that is inside the card.
- Context context = getContext();
- final ContentResolver cr = context.getContentResolver();
- final String primaryNumber = mPrimaryCall.getNumber();
- // Don't reload the image if the number is the same.
- if ((primaryNumber != null && !primaryNumber.equals(mLoadedNumber))
- || (primaryNumber == null && mLoadedNumber != null)) {
- BitmapWorkerTask.BitmapRunnable runnable = new BitmapWorkerTask.BitmapRunnable() {
- @Override
- public void run() {
- if (mBitmap != null) {
- Resources r = mSmallContactPhotoView.getResources();
- mSmallContactPhotoView.setImageDrawable(
- new CircleBitmapDrawable(r, mBitmap));
- mLargeContactPhotoView.setImageBitmap(mBitmap);
- mLargeContactPhotoView.clearColorFilter();
- } else {
- mSmallContactPhotoView.setImageResource(R.drawable.logo_avatar);
- mLargeContactPhotoView.setImageResource(R.drawable.ic_avatar_bg);
- }
-
- if (mSecondaryCall != null) {
- BitmapWorkerTask.BitmapRunnable secondCallContactPhotoHandler =
- new BitmapWorkerTask.BitmapRunnable() {
- @Override
- public void run() {
- if (mBitmap != null) {
- mLargeContactPhotoView.setImageBitmap(mBitmap);
- } else {
- mLargeContactPhotoView.setImageResource(
- R.drawable.logo_avatar);
- }
- }
- };
-
- BitmapWorkerTask.loadBitmap(
- cr, mLargeContactPhotoView, mSecondaryCall.getNumber(),
- secondCallContactPhotoHandler);
-
- int scrimColor = getResources().getColor(
- R.color.phone_secondary_call_scrim);
- mLargeContactPhotoView.setColorFilter(scrimColor);
- }
- mLoadedNumber = primaryNumber;
- }
- };
- BitmapWorkerTask.loadBitmap(cr, mLargeContactPhotoView, primaryNumber, runnable);
- }
-
- if (mSecondaryCall != null) {
- mSecondaryCallContainer.setVisibility(View.VISIBLE);
- if (mPrimaryCall.getState() == Call.STATE_ACTIVE
- && mSecondaryCall.getState() == Call.STATE_HOLDING) {
- mSecondaryCallControls.setVisibility(View.VISIBLE);
- } else {
- mSecondaryCallControls.setVisibility(View.GONE);
- }
- } else {
- mSecondaryCallContainer.setVisibility(View.GONE);
- mSecondaryCallControls.setVisibility(View.GONE);
- }
+ loadContactPhotoForPrimaryNumber(primaryCall.getNumber());
- String displayName = TelecomUtils.getDisplayName(context, mPrimaryCall);
+ String displayName = TelecomUtils.getDisplayName(getContext(), primaryCall);
mNameTextView.setText(displayName);
mNameTextView.setVisibility(TextUtils.isEmpty(displayName) ? View.GONE : View.VISIBLE);
- if (mSecondaryCall != null) {
- mSecondaryNameTextView.setText(
- TelecomUtils.getDisplayName(context, mSecondaryCall));
- }
-
- switch (mPrimaryCall.getState()) {
+ Context context = getContext();
+ switch (primaryCall.getState()) {
case Call.STATE_NEW:
// Since the content resolver call is only cached when a contact is found,
// this should only be called once on a new call to avoid jank.
// TODO: consider moving TelecomUtils.getTypeFromNumber into a CursorLoader
- String number = mPrimaryCall.getNumber();
- mCallInfoLabel = TelecomUtils.getTypeFromNumber(context, number);
+ mCallInfoLabel = TelecomUtils.getTypeFromNumber(context, primaryCall.getNumber());
case Call.STATE_CONNECTING:
case Call.STATE_DIALING:
case Call.STATE_SELECT_PHONE_ACCOUNT:
@@ -389,7 +330,7 @@ public class OngoingCallFragment extends Fragment {
case Call.STATE_DISCONNECTED:
mHandler.removeCallbacks(mUpdateDurationRunnable);
String callInfoText = TelecomUtils.getCallInfoText(context,
- mPrimaryCall, mCallInfoLabel);
+ primaryCall, mCallInfoLabel);
setStateText(callInfoText);
break;
case Call.STATE_ACTIVE:
@@ -401,17 +342,11 @@ public class OngoingCallFragment extends Fragment {
Log.w(TAG, "There should not be a ringing call in the ongoing call fragment.");
break;
default:
- Log.w(TAG, "Unhandled call state: " + mPrimaryCall.getState());
- }
-
- if (mSecondaryCall != null) {
- mSecondaryStateTextView.setText(
- TelecomUtils.callStateToUiString(context, mSecondaryCall.getState()));
+ Log.w(TAG, "Unhandled call state: " + primaryCall.getState());
}
// If it is a voicemail call, open the dialpad (with no animation).
- if (primaryNumber != null && primaryNumber.equals(
- TelecomUtils.getVoicemailNumber(context))) {
+ if (Objects.equals(primaryCall.getNumber(), TelecomUtils.getVoicemailNumber(context))) {
openDialpad(false /*animate*/);
mToggleDialpadButton.setVisibility(View.GONE);
} else {
@@ -419,7 +354,7 @@ public class OngoingCallFragment extends Fragment {
}
// Handle the holding case.
- if (mPrimaryCall.getState() == Call.STATE_HOLDING) {
+ if (primaryCall.getState() == Call.STATE_HOLDING) {
mEndCallButton.setVisibility(View.GONE);
mUnholdCallButton.setVisibility(View.VISIBLE);
mMuteButton.setVisibility(View.INVISIBLE);
@@ -430,32 +365,100 @@ public class OngoingCallFragment extends Fragment {
mMuteButton.setVisibility(View.VISIBLE);
mToggleDialpadButton.setVisibility(View.VISIBLE);
}
- }
- private void setStateText(CharSequence stateText) {
- mStateTextView.setText(stateText);
- mStateTextView.setVisibility(TextUtils.isEmpty(stateText) ? View.GONE : View.VISIBLE);
+ updateSecondaryCall(primaryCall, mUiCallManager.getSecondaryCall());
}
- private void updateCalls() {
- mPrimaryCall = mUiCallManager.getPrimaryCall();
- if (mPrimaryCall != null && mPrimaryCall.getState() == Call.STATE_RINGING) {
- // TODO: update when notifications will work
+ private void updateSecondaryCall(UiCall primaryCall, UiCall secondaryCall) {
+ if (primaryCall == null || secondaryCall == null) {
+ mSecondaryCallContainer.setVisibility(View.GONE);
+ mSecondaryCallControls.setVisibility(View.GONE);
+ return;
}
- mSecondaryCall = mUiCallManager.getSecondaryCall();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Primary call: " + mPrimaryCall + "\tSecondary call:" + mSecondaryCall);
+
+ mSecondaryCallContainer.setVisibility(View.VISIBLE);
+
+ if (primaryCall.getState() == Call.STATE_ACTIVE
+ && secondaryCall.getState() == Call.STATE_HOLDING) {
+ mSecondaryCallControls.setVisibility(View.VISIBLE);
+ } else {
+ mSecondaryCallControls.setVisibility(View.GONE);
}
- rebindViews();
+
+ Context context = getContext();
+ mSecondaryNameTextView.setText(TelecomUtils.getDisplayName(context, secondaryCall));
+ mSecondaryStateTextView.setText(
+ TelecomUtils.callStateToUiString(context, secondaryCall.getState()));
+
+ loadContactPhotoForSecondaryNumber(secondaryCall.getNumber());
}
/**
- * If the phone is using bluetooth:
- * * Do nothing
- * If the phone is not using bluetooth:
- * * If the phone supports bluetooth, use it.
- * * If the phone doesn't support bluetooth and support speaker, use speaker
- * * Otherwise, do nothing. Hopefully no phones won't have bt or speaker.
+ * Loads the contact photo associated with the given number and sets it in the views that
+ * correspond with a primary number.
+ */
+ private void loadContactPhotoForPrimaryNumber(String primaryNumber) {
+ // Don't reload the image if the number is the same.
+ if (Objects.equals(primaryNumber, mLoadedNumber)) {
+ return;
+ }
+
+ final ContentResolver cr = getContext().getContentResolver();
+ BitmapWorkerTask.BitmapRunnable runnable = new BitmapWorkerTask.BitmapRunnable() {
+ @Override
+ public void run() {
+ if (mBitmap != null) {
+ Resources r = getResources();
+ mSmallContactPhotoView.setImageDrawable(new CircleBitmapDrawable(r, mBitmap));
+ mLargeContactPhotoView.setImageBitmap(mBitmap);
+ mLargeContactPhotoView.clearColorFilter();
+ } else {
+ mSmallContactPhotoView.setImageResource(R.drawable.logo_avatar);
+ mLargeContactPhotoView.setImageResource(R.drawable.ic_avatar_bg);
+ }
+ }
+ };
+ mLoadedNumber = primaryNumber;
+ BitmapWorkerTask.loadBitmap(cr, mLargeContactPhotoView, primaryNumber, runnable);
+ }
+
+ /**
+ * Loads the contact photo associated with the given number and sets it in the views that
+ * correspond to a secondary number.
+ */
+ private void loadContactPhotoForSecondaryNumber(String secondaryNumber) {
+ BitmapWorkerTask.BitmapRunnable runnable = new BitmapWorkerTask.BitmapRunnable() {
+ @Override
+ public void run() {
+ if (mBitmap != null) {
+ mLargeContactPhotoView.setImageBitmap(mBitmap);
+ } else {
+ mLargeContactPhotoView.setImageResource(R.drawable.logo_avatar);
+ }
+ }
+ };
+
+ Context context = getContext();
+ BitmapWorkerTask.loadBitmap(context.getContentResolver(), mLargeContactPhotoView,
+ secondaryNumber, runnable);
+
+ int scrimColor = context.getColor(R.color.phone_secondary_call_scrim);
+ mLargeContactPhotoView.setColorFilter(scrimColor);
+ }
+
+ private void setStateText(CharSequence stateText) {
+ mStateTextView.setText(stateText);
+ mStateTextView.setVisibility(TextUtils.isEmpty(stateText) ? View.GONE : View.VISIBLE);
+ }
+
+ /**
+ * If the phone is using bluetooth, then do nothing. If the phone is not using bluetooth:
+ * <p>
+ * <ol>
+ * <li>If the phone supports bluetooth, use it.
+ * <li>If the phone doesn't support bluetooth and support speaker, use speaker
+ * <li>Otherwise, do nothing. Hopefully no phones won't have bt or speaker.
+ * </ol>
*/
private void trySpeakerAudioRouteIfNecessary() {
if (mUiCallManager == null) {
@@ -519,12 +522,12 @@ public class OngoingCallFragment extends Fragment {
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
v.setPressed(true);
- mUiCallManager.playDtmfTone(mPrimaryCall, digit);
+ mUiCallManager.playDtmfTone(mUiCallManager.getPrimaryCall(), digit);
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
v.setPressed(false);
v.performClick();
- mUiCallManager.stopDtmfTone(mPrimaryCall);
+ mUiCallManager.stopDtmfTone(mUiCallManager.getPrimaryCall());
return true;
}
@@ -547,11 +550,11 @@ public class OngoingCallFragment extends Fragment {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
v.setPressed(true);
- mUiCallManager.playDtmfTone(mPrimaryCall, digit);
+ mUiCallManager.playDtmfTone(mUiCallManager.getPrimaryCall(), digit);
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
v.setPressed(false);
- mUiCallManager.stopDtmfTone(mPrimaryCall);
+ mUiCallManager.stopDtmfTone(mUiCallManager.getPrimaryCall());
return true;
}
@@ -562,23 +565,21 @@ public class OngoingCallFragment extends Fragment {
private final Runnable mUpdateDurationRunnable = new Runnable() {
@Override
public void run() {
- if (mPrimaryCall.getState() != Call.STATE_ACTIVE) {
+ UiCall primaryCall = mUiCallManager.getPrimaryCall();
+ if (primaryCall.getState() != Call.STATE_ACTIVE) {
return;
}
String callInfoText = TelecomUtils.getCallInfoText(getContext(),
- mPrimaryCall, mCallInfoLabel);
+ primaryCall, mCallInfoLabel);
setStateText(callInfoText);
mHandler.postDelayed(this /* runnable */, DateUtils.SECOND_IN_MILLIS);
- }
- };
- private final Runnable mStopDtmfToneRunnable = new Runnable() {
- @Override
- public void run() {
- mUiCallManager.stopDtmfTone(mPrimaryCall);
}
};
+ private final Runnable mStopDtmfToneRunnable =
+ () -> mUiCallManager.stopDtmfTone(mUiCallManager.getPrimaryCall());
+
private final class DialpadAnimation extends Animation {
private static final int DURATION = 300;
private static final float MAX_SCRIM_ALPHA = 0.6f;
@@ -587,17 +588,16 @@ public class OngoingCallFragment extends Fragment {
private final int mScrimColor;
private final boolean mReverse;
- public DialpadAnimation(Context context, boolean reverse) {
+ DialpadAnimation(Context context, boolean reverse) {
this(context, reverse, true);
}
- public DialpadAnimation(Context context, boolean reverse, boolean animate) {
+ DialpadAnimation(Context context, boolean reverse, boolean animate) {
setDuration(animate ? DURATION : 0);
setInterpolator(new AccelerateDecelerateInterpolator());
- Resources res = context.getResources();
- mStartingTranslation =
- res.getDimensionPixelOffset(R.dimen.in_call_card_dialpad_translation_x);
- mScrimColor = res.getColor(R.color.phone_theme);
+ mStartingTranslation = context.getResources().getDimensionPixelOffset(
+ R.dimen.in_call_card_dialpad_translation_x);
+ mScrimColor = context.getColor(R.color.phone_theme);
mReverse = reverse;
}
@@ -624,11 +624,10 @@ public class OngoingCallFragment extends Fragment {
}
private final CallListener mCallListener = new CallListener() {
-
@Override
public void onCallAdded(UiCall call) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "on call added");
+ Log.d(TAG, "onCallAdded(); call: " + call);
}
updateCalls();
trySpeakerAudioRouteIfNecessary();
@@ -637,7 +636,7 @@ public class OngoingCallFragment extends Fragment {
@Override
public void onCallRemoved(UiCall call) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "on call removed");
+ Log.d(TAG, "onCallRemoved(); call: " + call);
}
mLastRemovedCall = call;
updateCalls();
@@ -647,7 +646,9 @@ public class OngoingCallFragment extends Fragment {
public void onAudioStateChanged(boolean isMuted, int audioRoute,
int supportedAudioRouteMask) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "on audio state changed");
+ Log.d(TAG, String.format("onAudioStateChanged(); isMuted: %b, audioRoute: %d, "
+ + " supportedAudioRouteMask: %d", isMuted, audioRoute,
+ supportedAudioRouteMask));
}
mMuteButton.setActivated(isMuted);
trySpeakerAudioRouteIfNecessary();
@@ -656,7 +657,7 @@ public class OngoingCallFragment extends Fragment {
@Override
public void onStateChanged(UiCall call, int state) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "onStateChanged");
+ Log.d(TAG, "onStateChanged(); call: " + call + ", state: " + state);
}
updateCalls();
}
@@ -664,7 +665,7 @@ public class OngoingCallFragment extends Fragment {
@Override
public void onCallUpdated(UiCall call) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "onCallUpdated");
+ Log.d(TAG, "onCallUpdated(); call: " + call);
}
updateCalls();
}
diff --git a/src/com/android/car/dialer/StrequentsAdapter.java b/src/com/android/car/dialer/StrequentsAdapter.java
index 78f4d3e6..981fb977 100644
--- a/src/com/android/car/dialer/StrequentsAdapter.java
+++ b/src/com/android/car/dialer/StrequentsAdapter.java
@@ -40,12 +40,11 @@ import java.util.List;
/**
* Adapter class for populating Contact data as loaded from the DB to an AA GroupingRecyclerView.
- *
- * <p>It handles two types of contacts:
- *
+ * It handles two types of contacts:
+ * <p>
* <ul>
- * <li>Strequent contacts (starred and/or frequent)</li>
- * <li>Last call contact</li>
+ * <li>Strequent contacts (starred and/or frequent)
+ * <li>Last call contact
* </ul>
*/
public class StrequentsAdapter extends RecyclerView.Adapter<CallLogViewHolder>
@@ -84,10 +83,6 @@ public class StrequentsAdapter extends RecyclerView.Adapter<CallLogViewHolder>
mStrequentsListener = listener;
}
- public void setFocusChangeListener(@Nullable View.OnFocusChangeListener listener) {
- mFocusChangeListener = listener;
- }
-
public void setLastCallCursor(@Nullable Cursor cursor) {
Log.e("StrequentsAdapter", "cursor: " + cursor);
Log.e("StrequentsAdapter", "count: " + (cursor == null ? 0 : cursor.getCount()));
@@ -304,7 +299,7 @@ public class StrequentsAdapter extends RecyclerView.Adapter<CallLogViewHolder>
// If we set this to 0, getRelativeTime will return null and no relative time
// will be displayed.
long millis = column == -1 ? 0 : cursor.getLong(column);
- StringBuffer secondaryText = new StringBuffer();
+ StringBuilder secondaryText = new StringBuilder();
CharSequence relativeDate = getRelativeTime(millis);
if (!isVoicemail) {
CharSequence type = TelecomUtils.getTypeFromNumber(mContext, number);
diff --git a/src/com/android/car/dialer/StrequentsFragment.java b/src/com/android/car/dialer/StrequentsFragment.java
index 69279c82..d0918336 100644
--- a/src/com/android/car/dialer/StrequentsFragment.java
+++ b/src/com/android/car/dialer/StrequentsFragment.java
@@ -18,7 +18,6 @@ package com.android.car.dialer;
import android.content.ContentResolver;
import android.content.Context;
import android.content.CursorLoader;
-import android.content.Loader;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Canvas;
@@ -27,13 +26,13 @@ import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
-import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+
import com.android.car.dialer.telecom.PhoneLoader;
import com.android.car.dialer.telecom.UiCallManager;
import com.android.car.view.PagedListView;
@@ -45,8 +44,8 @@ import com.android.car.view.PagedListView;
public class StrequentsFragment extends Fragment {
private static final String TAG = "Em.StrequentsFrag";
- public static final String KEY_MAX_CLICKS = "max_clicks";
- public static final int DEFAULT_MAX_CLICKS = 6;
+ private static final String KEY_MAX_CLICKS = "max_clicks";
+ private static final int DEFAULT_MAX_CLICKS = 6;
private UiCallManager mUiCallManager;
private StrequentsAdapter mAdapter;
@@ -85,7 +84,6 @@ public class StrequentsFragment extends Fragment {
mListView = (PagedListView) view.findViewById(R.id.list_view);
mListView.getLayoutManager().setOffsetRows(true);
- Bundle args = getArguments();
mSpeedialCursorLoader = PhoneLoader.registerCallObserver(PhoneLoader.CALL_TYPE_SPEED_DIAL,
mContext, (loader, cursor) -> {
if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -115,9 +113,10 @@ public class StrequentsFragment extends Fragment {
false, new CallLogContentObserver(new Handler()));
// Maximum number of forward acting clicks the user can perform
-
- int maxClicks = args.getInt(KEY_MAX_CLICKS,
- DEFAULT_MAX_CLICKS /* G.maxForwardClicks.get() */);
+ Bundle args = getArguments();
+ int maxClicks = args == null
+ ? DEFAULT_MAX_CLICKS
+ : args.getInt(KEY_MAX_CLICKS, DEFAULT_MAX_CLICKS /* G.maxForwardClicks.get() */);
// We want to show one fewer page than max clicks to allow clicking on an item,
// but, the first page is "free" since it doesn't take any clicks to show
final int maxPages = maxClicks < 0 ? -1 : maxClicks;
@@ -299,7 +298,7 @@ public class StrequentsFragment extends Fragment {
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
int bottom = child.getBottom() + lp.bottomMargin
- + Math.round(ViewCompat.getTranslationY(child));
+ + Math.round(child.getTranslationY());
int top = bottom - mDividerHeight;
if (top >= c.getHeight() || top < 0) {
diff --git a/src/com/android/car/dialer/TelecomActivity.java b/src/com/android/car/dialer/TelecomActivity.java
index 33049ede..d59fcc23 100644
--- a/src/com/android/car/dialer/TelecomActivity.java
+++ b/src/com/android/car/dialer/TelecomActivity.java
@@ -22,6 +22,8 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar.LayoutParams;
@@ -57,29 +59,29 @@ import static android.support.v7.widget.Toolbar.LayoutParams.MATCH_PARENT;
*/
public class TelecomActivity extends CarDrawerActivity implements
DialerFragment.DialerBackButtonListener {
- private static final String TAG = "Em.TelecomActivity";
+ private static final String TAG = "TelecomActivity";
private static final String ACTION_ANSWER_CALL = "com.android.car.dialer.ANSWER_CALL";
private static final String ACTION_END_CALL = "com.android.car.dialer.END_CALL";
+
private static final String DIALER_BACKSTACK = "DialerBackstack";
- private static final String FRAGMENT_CLASS_KEY = "FRAGMENT_CLASS_KEY";
+ private static final String CONTENT_FRAGMENT_TAG = "CONTENT_FRAGMENT_TAG";
+ private static final String DIALER_FRAGMENT_TAG = "DIALER_FRAGMENT_TAG";
private final UiBluetoothMonitor.Listener mBluetoothListener = this::updateCurrentFragment;
private UiCallManager mUiCallManager;
private UiBluetoothMonitor mUiBluetoothMonitor;
- private Fragment mCurrentFragment;
- private String mCurrentFragmentName;
-
- private int mLastNoHfpMessageId;
- private StrequentsFragment mSpeedDialFragment;
- private Fragment mOngoingCallFragment;
-
- private DialerFragment mDialerFragment;
- private boolean mDialerFragmentOpened;
-
- private SearchView mSearchView;
+ /**
+ * Whether or not it is safe to make transactions on the
+ * {@link android.support.v4.app.FragmentManager}. This variable prevents a possible exception
+ * when calling commit() on the FragmentManager.
+ *
+ * <p>The default value is {@code true} because it is only after
+ * {@link #onSaveInstanceState(Bundle)} that fragment commits are not allowed.
+ */
+ private boolean mAllowFragmentCommits = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -93,14 +95,6 @@ public class TelecomActivity extends CarDrawerActivity implements
mUiCallManager = new UiCallManager(this);
mUiBluetoothMonitor = new UiBluetoothMonitor(this);
-
- if (savedInstanceState != null) {
- mCurrentFragmentName = savedInstanceState.getString(FRAGMENT_CLASS_KEY);
- }
-
- if (vdebug()) {
- Log.d(TAG, "onCreate done, mCurrentFragmentName: " + mCurrentFragmentName);
- }
}
@Override
@@ -131,9 +125,7 @@ public class TelecomActivity extends CarDrawerActivity implements
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
-
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
- mSearchView = searchView;
return super.onCreateOptionsMenu(menu);
}
@@ -149,17 +141,17 @@ public class TelecomActivity extends CarDrawerActivity implements
}
@Override
- protected void onPause() {
- super.onPause();
+ protected void onStop() {
+ super.onStop();
mUiCallManager.removeListener(mCarCallListener);
mUiBluetoothMonitor.removeListener(mBluetoothListener);
}
@Override
public void onSaveInstanceState(Bundle outState) {
- if (mCurrentFragment != null) {
- outState.putString(FRAGMENT_CLASS_KEY, mCurrentFragmentName);
- }
+ // A transaction can only be committed with this method prior to its containing activity
+ // saving its state.
+ mAllowFragmentCommits = false;
super.onSaveInstanceState(outState);
}
@@ -170,11 +162,15 @@ public class TelecomActivity extends CarDrawerActivity implements
}
@Override
- protected void onResume() {
+ protected void onStart() {
if (vdebug()) {
- Log.d(TAG, "onResume");
+ Log.d(TAG, "onStart");
}
- super.onResume();
+ super.onStart();
+
+ // Fragment commits are not allowed once the Activity's state has been saved. Once
+ // onStart() has been called, the FragmentManager should now allow commits.
+ mAllowFragmentCommits = true;
// Update the current fragment before handling the intent so that any UI updates in
// handleIntent() is not overridden by updateCurrentFragment().
@@ -185,27 +181,6 @@ public class TelecomActivity extends CarDrawerActivity implements
mUiBluetoothMonitor.addListener(mBluetoothListener);
}
- // TODO: move to base class.
- private void setContentFragmentWithAnimations(Fragment fragment, int enter, int exit) {
- if (vdebug()) {
- Log.d(TAG, "setContentFragmentWithAnimations: " + fragment);
- }
-
- maybeHideDialer();
-
- getSupportFragmentManager().beginTransaction()
- .setCustomAnimations(enter, exit)
- .replace(getContentContainerId(), fragment)
- .commitAllowingStateLoss();
-
- mCurrentFragmentName = fragment.getClass().getSimpleName();
- mCurrentFragment = fragment;
-
- if (vdebug()) {
- Log.d(TAG, "setContentFragmentWithAnimations, fragmentName:" + mCurrentFragmentName);
- }
- }
-
private void handleIntent() {
Intent intent = getIntent();
String action = intent != null ? intent.getAction() : null;
@@ -240,14 +215,15 @@ public class TelecomActivity extends CarDrawerActivity implements
case Intent.ACTION_DIAL:
String number = PhoneNumberUtils.getNumberFromIntent(intent, this);
- if (!(mCurrentFragment instanceof NoHfpFragment)) {
- showDialerWithNumber(number);
+ if (!(getCurrentFragment() instanceof NoHfpFragment)) {
+ showDialer(number);
}
break;
case SEARCH_SUGGESTION_CLICKED:
Uri contactUri = intent.getData();
- showContactDetailFragment(contactUri);
+ setContentFragment(
+ ContactDetailsFragment.newInstance(contactUri, mUiCallManager));
break;
default:
@@ -258,15 +234,13 @@ public class TelecomActivity extends CarDrawerActivity implements
}
/**
- * Will switch to the drawer or no-hfp fragment as necessary.
+ * Updates the content fragment of this Activity based on the state of the application.
*/
private void updateCurrentFragment() {
if (vdebug()) {
- Log.d(TAG, "updateCurrentFragment");
+ Log.d(TAG, "updateCurrentFragment()");
}
- // TODO: do nothing when activity isFinishing() == true.
-
boolean callEmpty = mUiCallManager.getCalls().isEmpty();
if (!mUiBluetoothMonitor.isBluetoothEnabled() && callEmpty) {
showNoHfpFragment(R.string.bluetooth_disabled);
@@ -279,15 +253,13 @@ public class TelecomActivity extends CarDrawerActivity implements
if (vdebug()) {
Log.d(TAG, "ongoingCall: " + ongoingCall + ", mCurrentFragment: "
- + mCurrentFragment);
+ + getCurrentFragment());
}
- if (ongoingCall == null && mCurrentFragment instanceof OngoingCallFragment) {
+ if (ongoingCall == null && getCurrentFragment() instanceof OngoingCallFragment) {
showSpeedDialFragment();
} else if (ongoingCall != null) {
showOngoingCallFragment();
- } else if (DialerFragment.class.getSimpleName().equals(mCurrentFragmentName)) {
- showDialer();
} else {
showSpeedDialFragment();
}
@@ -303,20 +275,15 @@ public class TelecomActivity extends CarDrawerActivity implements
Log.d(TAG, "showSpeedDialFragment");
}
- if (mCurrentFragment instanceof StrequentsFragment) {
+ if (!mAllowFragmentCommits || getCurrentFragment() instanceof StrequentsFragment) {
return;
}
- if (mSpeedDialFragment == null) {
- mSpeedDialFragment = StrequentsFragment.newInstance(mUiCallManager);
- Bundle args = new Bundle();
- mSpeedDialFragment.setArguments(args);
- }
-
- if (mCurrentFragment instanceof DialerFragment) {
- setContentFragmentWithSlideAndDelayAnimation(mSpeedDialFragment);
+ Fragment fragment = StrequentsFragment.newInstance(mUiCallManager);
+ if (getCurrentFragment() instanceof DialerFragment) {
+ setContentFragmentWithSlideAndDelayAnimation(fragment);
} else {
- setContentFragmentWithFadeAnimation(mSpeedDialFragment);
+ setContentFragmentWithFadeAnimation(fragment);
}
}
@@ -324,40 +291,39 @@ public class TelecomActivity extends CarDrawerActivity implements
if (vdebug()) {
Log.d(TAG, "showOngoingCallFragment");
}
- if (mCurrentFragment instanceof OngoingCallFragment) {
+ if (!mAllowFragmentCommits || getCurrentFragment() instanceof OngoingCallFragment) {
closeDrawer();
return;
}
- if (mOngoingCallFragment == null) {
- mOngoingCallFragment =
- OngoingCallFragment.newInstance(mUiCallManager, mUiBluetoothMonitor);
+ Fragment fragment = OngoingCallFragment.newInstance(mUiCallManager, mUiBluetoothMonitor);
+ setContentFragmentWithFadeAnimation(fragment);
+ closeDrawer();
+ }
+
+ private void showDialer() {
+ if (vdebug()) {
+ Log.d(TAG, "showDialer");
}
- setContentFragmentWithFadeAnimation(mOngoingCallFragment);
- closeDrawer();
+ showDialer(null /* dialNumber */);
}
/**
- * Displays the {@link DialerFragment} on top of the contents of the TelecomActivity.
+ * Displays the {@link DialerFragment} and initialize it with the given phone number.
*/
- private void showDialer() {
+ private void showDialer(@Nullable String dialNumber) {
if (vdebug()) {
- Log.d(TAG, "showDialer");
+ Log.d(TAG, "showDialer with number: " + dialNumber);
}
- if (mDialerFragmentOpened) {
+ if (!mAllowFragmentCommits ||
+ getSupportFragmentManager().findFragmentByTag(DIALER_FRAGMENT_TAG) != null) {
return;
}
- if (mDialerFragment == null) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "showDialer: creating dialer");
- }
-
- mDialerFragment = DialerFragment.newInstance(mUiCallManager);
- mDialerFragment.setDialerBackButtonListener(this);
- }
+ Fragment fragment =
+ DialerFragment.newInstance(mUiCallManager, this /* listener */, dialNumber);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "adding dialer to fragment backstack");
@@ -367,11 +333,9 @@ public class TelecomActivity extends CarDrawerActivity implements
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.telecom_slide_in, R.anim.telecom_slide_out,
R.anim.telecom_slide_in, R.anim.telecom_slide_out)
- .add(getContentContainerId(), mDialerFragment)
+ .add(getContentContainerId(), fragment, DIALER_FRAGMENT_TAG)
.addToBackStack(DIALER_BACKSTACK)
- .commitAllowingStateLoss();
-
- mDialerFragmentOpened = true;
+ .commit();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "done adding fragment to backstack");
@@ -382,10 +346,10 @@ public class TelecomActivity extends CarDrawerActivity implements
* Checks if the dialpad fragment is opened and hides it if it is.
*/
private void maybeHideDialer() {
- if (mDialerFragmentOpened) {
- // Dismiss the dialer by removing it from the back stack.
+ // The dialer is the only fragment to be added to the back stack. Dismiss the dialer by
+ // removing it from the back stack.
+ if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
- mDialerFragmentOpened = false;
}
}
@@ -394,30 +358,19 @@ public class TelecomActivity extends CarDrawerActivity implements
maybeHideDialer();
}
- private void showDialerWithNumber(String number) {
- showDialer();
- mDialerFragment.setDialNumber(number);
- }
-
- private void showNoHfpFragment(int stringResId) {
- if (mCurrentFragment instanceof NoHfpFragment && stringResId == mLastNoHfpMessageId) {
+ private void showNoHfpFragment(@StringRes int stringResId) {
+ if (!mAllowFragmentCommits) {
return;
}
- mLastNoHfpMessageId = stringResId;
String errorMessage = getString(stringResId);
- NoHfpFragment frag = new NoHfpFragment();
- frag.setErrorMessage(errorMessage);
- setContentFragment(frag);
- mCurrentFragment = frag;
- }
+ Fragment currentFragment = getCurrentFragment();
-
- private void showContactDetailFragment(Uri contactUri) {
- ContactDetailsFragment fragment =
- ContactDetailsFragment.newInstance(contactUri, mUiCallManager);
- setContentFragment(fragment);
- mCurrentFragment = fragment;
+ if (currentFragment instanceof NoHfpFragment) {
+ ((NoHfpFragment) currentFragment).setErrorMessage(errorMessage);
+ } else {
+ setContentFragment(NoHfpFragment.newInstance(errorMessage));
+ }
}
private void setContentFragmentWithSlideAndDelayAnimation(Fragment fragment) {
@@ -436,6 +389,41 @@ public class TelecomActivity extends CarDrawerActivity implements
R.anim.telecom_fade_in, R.anim.telecom_fade_out);
}
+ private void setContentFragmentWithAnimations(Fragment fragment, int enter, int exit) {
+ if (vdebug()) {
+ Log.d(TAG, "setContentFragmentWithAnimations: " + fragment);
+ }
+
+ maybeHideDialer();
+ getSupportFragmentManager().beginTransaction()
+ .setCustomAnimations(enter, exit)
+ .replace(getContentContainerId(), fragment, CONTENT_FRAGMENT_TAG)
+ .commitNow();
+ }
+
+ /**
+ * Sets the fragment that will be shown as the main content of this Activity. Note that this
+ * fragment is not always visible. In particular, the dialer fragment can show up on top of this
+ * fragment.
+ */
+ private void setContentFragment(Fragment fragment) {
+ maybeHideDialer();
+ getSupportFragmentManager().beginTransaction()
+ .replace(getContentContainerId(), fragment, CONTENT_FRAGMENT_TAG)
+ .commitNow();
+ }
+
+ /**
+ * Returns the fragment that is currently being displayed as the content view. Note that this
+ * is not necessarily the fragment that is visible. For example, the returned fragment
+ * could be the content, but the dial fragment is being displayed on top of it. Check for
+ * the existence of the dial fragment with the TAG {@link #DIALER_FRAGMENT_TAG}.
+ */
+ @Nullable
+ private Fragment getCurrentFragment() {
+ return getSupportFragmentManager().findFragmentByTag(CONTENT_FRAGMENT_TAG);
+ }
+
private final CallListener mCarCallListener = new UiCallManager.CallListener() {
@Override
public void onCallAdded(UiCall call) {
@@ -470,12 +458,6 @@ public class TelecomActivity extends CarDrawerActivity implements
}
};
- private void setContentFragment(Fragment fragment) {
- getSupportFragmentManager().beginTransaction()
- .replace(getContentContainerId(), fragment)
- .commit();
- }
-
private static boolean vdebug() {
return Log.isLoggable(TAG, Log.DEBUG);
}
@@ -506,9 +488,10 @@ public class TelecomActivity extends CarDrawerActivity implements
@Override
public void populateViewHolder(DrawerItemViewHolder holder, int position) {
- holder.getTitle().setText(mItems.get(position).mTitle);
- holder.getText().setText(mItems.get(position).mText);
- holder.getIcon().setImageBitmap(mItems.get(position).mIcon);
+ CallLogListingTask.CallLogItem item = mItems.get(position);
+ holder.getTitle().setText(item.mTitle);
+ holder.getText().setText(item.mText);
+ holder.getIcon().setImageBitmap(item.mIcon);
}
@Override