• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.incallui.incall.impl;
18 
19 import android.Manifest.permission;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.os.Build.VERSION;
23 import android.os.Build.VERSION_CODES;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.support.annotation.ColorInt;
27 import android.support.annotation.NonNull;
28 import android.support.annotation.Nullable;
29 import android.support.v4.app.Fragment;
30 import android.support.v4.app.FragmentTransaction;
31 import android.support.v4.content.ContextCompat;
32 import android.telecom.CallAudioState;
33 import android.telephony.TelephonyManager;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.View.OnClickListener;
37 import android.view.ViewGroup;
38 import android.view.accessibility.AccessibilityEvent;
39 import android.widget.ImageView;
40 import android.widget.RelativeLayout;
41 import android.widget.Toast;
42 import com.android.dialer.common.Assert;
43 import com.android.dialer.common.FragmentUtils;
44 import com.android.dialer.common.LogUtil;
45 import com.android.dialer.compat.ActivityCompat;
46 import com.android.dialer.logging.DialerImpression;
47 import com.android.dialer.logging.Logger;
48 import com.android.dialer.multimedia.MultimediaData;
49 import com.android.dialer.strictmode.StrictModeUtils;
50 import com.android.dialer.util.ViewUtil;
51 import com.android.dialer.widget.LockableViewPager;
52 import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment;
53 import com.android.incallui.audioroute.AudioRouteSelectorDialogFragment.AudioRouteSelectorPresenter;
54 import com.android.incallui.contactgrid.ContactGridManager;
55 import com.android.incallui.hold.OnHoldFragment;
56 import com.android.incallui.incall.impl.ButtonController.SpeakerButtonController;
57 import com.android.incallui.incall.impl.InCallButtonGridFragment.OnButtonGridCreatedListener;
58 import com.android.incallui.incall.protocol.InCallButtonIds;
59 import com.android.incallui.incall.protocol.InCallButtonIdsExtension;
60 import com.android.incallui.incall.protocol.InCallButtonUi;
61 import com.android.incallui.incall.protocol.InCallButtonUiDelegate;
62 import com.android.incallui.incall.protocol.InCallButtonUiDelegateFactory;
63 import com.android.incallui.incall.protocol.InCallScreen;
64 import com.android.incallui.incall.protocol.InCallScreenDelegate;
65 import com.android.incallui.incall.protocol.InCallScreenDelegateFactory;
66 import com.android.incallui.incall.protocol.PrimaryCallState;
67 import com.android.incallui.incall.protocol.PrimaryCallState.ButtonState;
68 import com.android.incallui.incall.protocol.PrimaryInfo;
69 import com.android.incallui.incall.protocol.SecondaryInfo;
70 import java.util.ArrayList;
71 import java.util.List;
72 
73 /** Fragment that shows UI for an ongoing voice call. */
74 public class InCallFragment extends Fragment
75     implements InCallScreen,
76         InCallButtonUi,
77         OnClickListener,
78         AudioRouteSelectorPresenter,
79         OnButtonGridCreatedListener {
80 
81   private List<ButtonController> buttonControllers = new ArrayList<>();
82   private View endCallButton;
83   private InCallPaginator paginator;
84   private LockableViewPager pager;
85   private InCallPagerAdapter adapter;
86   private ContactGridManager contactGridManager;
87   private InCallScreenDelegate inCallScreenDelegate;
88   private InCallButtonUiDelegate inCallButtonUiDelegate;
89   private InCallButtonGridFragment inCallButtonGridFragment;
90   @Nullable private ButtonChooser buttonChooser;
91   private SecondaryInfo savedSecondaryInfo;
92   private int voiceNetworkType;
93   private int phoneType;
94   private boolean stateRestored;
95 
96   // Add animation to educate users. If a call has enriched calling attachments then we'll
97   // initially show the attachment page. After a delay seconds we'll animate to the button grid.
98   private final Handler handler = new Handler();
99   private final Runnable pagerRunnable =
100       new Runnable() {
101         @Override
102         public void run() {
103           pager.setCurrentItem(adapter.getButtonGridPosition());
104         }
105       };
106 
isSupportedButton(@nCallButtonIds int id)107   private static boolean isSupportedButton(@InCallButtonIds int id) {
108     return id == InCallButtonIds.BUTTON_AUDIO
109         || id == InCallButtonIds.BUTTON_MUTE
110         || id == InCallButtonIds.BUTTON_DIALPAD
111         || id == InCallButtonIds.BUTTON_HOLD
112         || id == InCallButtonIds.BUTTON_SWAP
113         || id == InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO
114         || id == InCallButtonIds.BUTTON_ADD_CALL
115         || id == InCallButtonIds.BUTTON_MERGE
116         || id == InCallButtonIds.BUTTON_MANAGE_VOICE_CONFERENCE
117         || id == InCallButtonIds.BUTTON_SWAP_SIM;
118   }
119 
120   @Override
onAttach(Context context)121   public void onAttach(Context context) {
122     super.onAttach(context);
123     if (savedSecondaryInfo != null) {
124       setSecondary(savedSecondaryInfo);
125     }
126   }
127 
128   @Override
onCreate(Bundle savedInstanceState)129   public void onCreate(Bundle savedInstanceState) {
130     super.onCreate(savedInstanceState);
131     inCallButtonUiDelegate =
132         FragmentUtils.getParent(this, InCallButtonUiDelegateFactory.class)
133             .newInCallButtonUiDelegate();
134     if (savedInstanceState != null) {
135       inCallButtonUiDelegate.onRestoreInstanceState(savedInstanceState);
136       stateRestored = true;
137     }
138   }
139 
140   @Nullable
141   @Override
onCreateView( @onNull LayoutInflater layoutInflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle)142   public View onCreateView(
143       @NonNull LayoutInflater layoutInflater,
144       @Nullable ViewGroup viewGroup,
145       @Nullable Bundle bundle) {
146     LogUtil.i("InCallFragment.onCreateView", null);
147     // Bypass to avoid StrictModeResourceMismatchViolation
148     final View view =
149         StrictModeUtils.bypass(
150             () -> layoutInflater.inflate(R.layout.frag_incall_voice, viewGroup, false));
151     contactGridManager =
152         new ContactGridManager(
153             view,
154             (ImageView) view.findViewById(R.id.contactgrid_avatar),
155             getResources().getDimensionPixelSize(R.dimen.incall_avatar_size),
156             true /* showAnonymousAvatar */);
157     contactGridManager.onMultiWindowModeChanged(ActivityCompat.isInMultiWindowMode(getActivity()));
158 
159     paginator = (InCallPaginator) view.findViewById(R.id.incall_paginator);
160     pager = (LockableViewPager) view.findViewById(R.id.incall_pager);
161     pager.setOnTouchListener(
162         (v, event) -> {
163           handler.removeCallbacks(pagerRunnable);
164           return false;
165         });
166 
167     endCallButton = view.findViewById(R.id.incall_end_call);
168     endCallButton.setOnClickListener(this);
169 
170     if (ContextCompat.checkSelfPermission(getContext(), permission.READ_PHONE_STATE)
171         != PackageManager.PERMISSION_GRANTED) {
172       voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
173     } else {
174 
175       voiceNetworkType =
176           VERSION.SDK_INT >= VERSION_CODES.N
177               ? getContext().getSystemService(TelephonyManager.class).getVoiceNetworkType()
178               : TelephonyManager.NETWORK_TYPE_UNKNOWN;
179     }
180     // TODO(a bug): Change to use corresponding phone type used for current call.
181     phoneType = getContext().getSystemService(TelephonyManager.class).getPhoneType();
182     View space = view.findViewById(R.id.navigation_bar_background);
183     space.getLayoutParams().height = ViewUtil.getNavigationBarHeight(getContext());
184 
185     return view;
186   }
187 
188   @Override
onResume()189   public void onResume() {
190     super.onResume();
191     inCallButtonUiDelegate.refreshMuteState();
192     inCallScreenDelegate.onInCallScreenResumed();
193   }
194 
195   @Override
onViewCreated(@onNull View view, @Nullable Bundle bundle)196   public void onViewCreated(@NonNull View view, @Nullable Bundle bundle) {
197     LogUtil.i("InCallFragment.onViewCreated", null);
198     super.onViewCreated(view, bundle);
199     inCallScreenDelegate =
200         FragmentUtils.getParent(this, InCallScreenDelegateFactory.class).newInCallScreenDelegate();
201     Assert.isNotNull(inCallScreenDelegate);
202 
203     buttonControllers.add(new ButtonController.MuteButtonController(inCallButtonUiDelegate));
204     buttonControllers.add(new ButtonController.SpeakerButtonController(inCallButtonUiDelegate));
205     buttonControllers.add(new ButtonController.DialpadButtonController(inCallButtonUiDelegate));
206     buttonControllers.add(new ButtonController.HoldButtonController(inCallButtonUiDelegate));
207     buttonControllers.add(new ButtonController.AddCallButtonController(inCallButtonUiDelegate));
208     buttonControllers.add(new ButtonController.SwapButtonController(inCallButtonUiDelegate));
209     buttonControllers.add(new ButtonController.MergeButtonController(inCallButtonUiDelegate));
210     buttonControllers.add(new ButtonController.SwapSimButtonController(inCallButtonUiDelegate));
211     buttonControllers.add(
212         new ButtonController.UpgradeToVideoButtonController(inCallButtonUiDelegate));
213     buttonControllers.add(
214         new ButtonController.ManageConferenceButtonController(inCallScreenDelegate));
215     buttonControllers.add(
216         new ButtonController.SwitchToSecondaryButtonController(inCallScreenDelegate));
217 
218     inCallScreenDelegate.onInCallScreenDelegateInit(this);
219     inCallScreenDelegate.onInCallScreenReady();
220   }
221 
222   @Override
onPause()223   public void onPause() {
224     super.onPause();
225     inCallScreenDelegate.onInCallScreenPaused();
226   }
227 
228   @Override
onDestroyView()229   public void onDestroyView() {
230     super.onDestroyView();
231     inCallScreenDelegate.onInCallScreenUnready();
232   }
233 
234   @Override
onSaveInstanceState(Bundle outState)235   public void onSaveInstanceState(Bundle outState) {
236     super.onSaveInstanceState(outState);
237     inCallButtonUiDelegate.onSaveInstanceState(outState);
238   }
239 
240   @Override
onClick(View view)241   public void onClick(View view) {
242     if (view == endCallButton) {
243       LogUtil.i("InCallFragment.onClick", "end call button clicked");
244       Logger.get(getContext())
245           .logImpression(DialerImpression.Type.IN_CALL_DIALPAD_HANG_UP_BUTTON_PRESSED);
246       inCallScreenDelegate.onEndCallClicked();
247     } else {
248       LogUtil.e("InCallFragment.onClick", "unknown view: " + view);
249       Assert.fail();
250     }
251   }
252 
253   @Override
setPrimary(@onNull PrimaryInfo primaryInfo)254   public void setPrimary(@NonNull PrimaryInfo primaryInfo) {
255     LogUtil.i("InCallFragment.setPrimary", primaryInfo.toString());
256     setAdapterMedia(primaryInfo.multimediaData(), primaryInfo.showInCallButtonGrid());
257     contactGridManager.setPrimary(primaryInfo);
258 
259     if (primaryInfo.shouldShowLocation()) {
260       // Hide the avatar to make room for location
261       contactGridManager.setAvatarHidden(true);
262 
263       // Need to let the dialpad move up a little further when location info is being shown
264       View dialpadView = getView().findViewById(R.id.incall_dialpad_container);
265       ViewGroup.LayoutParams params = dialpadView.getLayoutParams();
266       if (params instanceof RelativeLayout.LayoutParams) {
267         ((RelativeLayout.LayoutParams) params).removeRule(RelativeLayout.BELOW);
268       }
269       dialpadView.setLayoutParams(params);
270     }
271   }
272 
setAdapterMedia(MultimediaData multimediaData, boolean showInCallButtonGrid)273   private void setAdapterMedia(MultimediaData multimediaData, boolean showInCallButtonGrid) {
274     if (adapter == null) {
275       adapter =
276           new InCallPagerAdapter(getChildFragmentManager(), multimediaData, showInCallButtonGrid);
277       pager.setAdapter(adapter);
278     } else {
279       adapter.setAttachments(multimediaData);
280     }
281 
282     if (adapter.getCount() > 1 && getResources().getInteger(R.integer.incall_num_rows) > 1) {
283       paginator.setVisibility(View.VISIBLE);
284       paginator.setupWithViewPager(pager);
285       pager.setSwipingLocked(false);
286       if (!stateRestored) {
287         handler.postDelayed(pagerRunnable, 4_000);
288       } else {
289         pager.setCurrentItem(adapter.getButtonGridPosition(), false /* animateScroll */);
290       }
291     } else {
292       paginator.setVisibility(View.GONE);
293     }
294   }
295 
296   @Override
setSecondary(@onNull SecondaryInfo secondaryInfo)297   public void setSecondary(@NonNull SecondaryInfo secondaryInfo) {
298     LogUtil.i("InCallFragment.setSecondary", secondaryInfo.toString());
299     updateButtonStates();
300 
301     if (!isAdded()) {
302       savedSecondaryInfo = secondaryInfo;
303       return;
304     }
305     savedSecondaryInfo = null;
306     FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
307     Fragment oldBanner = getChildFragmentManager().findFragmentById(R.id.incall_on_hold_banner);
308     if (secondaryInfo.shouldShow()) {
309       transaction.replace(R.id.incall_on_hold_banner, OnHoldFragment.newInstance(secondaryInfo));
310     } else {
311       if (oldBanner != null) {
312         transaction.remove(oldBanner);
313       }
314     }
315     transaction.setCustomAnimations(R.anim.abc_slide_in_top, R.anim.abc_slide_out_top);
316     transaction.commitNowAllowingStateLoss();
317   }
318 
319   @Override
setCallState(@onNull PrimaryCallState primaryCallState)320   public void setCallState(@NonNull PrimaryCallState primaryCallState) {
321     LogUtil.i("InCallFragment.setCallState", primaryCallState.toString());
322     contactGridManager.setCallState(primaryCallState);
323     getButtonController(InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY)
324         .setAllowed(primaryCallState.swapToSecondaryButtonState() != ButtonState.NOT_SUPPORT);
325     getButtonController(InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY)
326         .setEnabled(primaryCallState.swapToSecondaryButtonState() == ButtonState.ENABLED);
327     buttonChooser =
328         ButtonChooserFactory.newButtonChooser(
329             voiceNetworkType, primaryCallState.isWifi(), phoneType);
330     updateButtonStates();
331   }
332 
333   @Override
setEndCallButtonEnabled(boolean enabled, boolean animate)334   public void setEndCallButtonEnabled(boolean enabled, boolean animate) {
335     if (endCallButton != null) {
336       endCallButton.setEnabled(enabled);
337     }
338   }
339 
340   @Override
showManageConferenceCallButton(boolean visible)341   public void showManageConferenceCallButton(boolean visible) {
342     getButtonController(InCallButtonIds.BUTTON_MANAGE_VOICE_CONFERENCE).setAllowed(visible);
343     getButtonController(InCallButtonIds.BUTTON_MANAGE_VOICE_CONFERENCE).setEnabled(visible);
344     updateButtonStates();
345   }
346 
347   @Override
isManageConferenceVisible()348   public boolean isManageConferenceVisible() {
349     return getButtonController(InCallButtonIds.BUTTON_MANAGE_VOICE_CONFERENCE).isAllowed();
350   }
351 
352   @Override
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)353   public void dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
354     contactGridManager.dispatchPopulateAccessibilityEvent(event);
355   }
356 
357   @Override
showNoteSentToast()358   public void showNoteSentToast() {
359     LogUtil.i("InCallFragment.showNoteSentToast", null);
360     Toast.makeText(getContext(), R.string.incall_note_sent, Toast.LENGTH_LONG).show();
361   }
362 
363   @Override
updateInCallScreenColors()364   public void updateInCallScreenColors() {}
365 
366   @Override
onInCallScreenDialpadVisibilityChange(boolean isShowing)367   public void onInCallScreenDialpadVisibilityChange(boolean isShowing) {
368     LogUtil.i("InCallFragment.onInCallScreenDialpadVisibilityChange", "isShowing: " + isShowing);
369     // Take note that the dialpad button isShowing
370     getButtonController(InCallButtonIds.BUTTON_DIALPAD).setChecked(isShowing);
371 
372     // This check is needed because there is a race condition where we attempt to update
373     // ButtonGridFragment before it is ready, so we check whether it is ready first and once it is
374     // ready, #onButtonGridCreated will mark the dialpad button as isShowing.
375     if (inCallButtonGridFragment != null) {
376       // Update the Android Button's state to isShowing.
377       inCallButtonGridFragment.onInCallScreenDialpadVisibilityChange(isShowing);
378     }
379   }
380 
381   @Override
getAnswerAndDialpadContainerResourceId()382   public int getAnswerAndDialpadContainerResourceId() {
383     return R.id.incall_dialpad_container;
384   }
385 
386   @Override
getInCallScreenFragment()387   public Fragment getInCallScreenFragment() {
388     return this;
389   }
390 
391   @Override
showButton(@nCallButtonIds int buttonId, boolean show)392   public void showButton(@InCallButtonIds int buttonId, boolean show) {
393     LogUtil.v(
394         "InCallFragment.showButton",
395         "buttionId: %s, show: %b",
396         InCallButtonIdsExtension.toString(buttonId),
397         show);
398     if (isSupportedButton(buttonId)) {
399       getButtonController(buttonId).setAllowed(show);
400       if (buttonId == InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO && show) {
401         Logger.get(getContext())
402             .logImpression(DialerImpression.Type.UPGRADE_TO_VIDEO_CALL_BUTTON_SHOWN);
403       }
404     }
405   }
406 
407   @Override
enableButton(@nCallButtonIds int buttonId, boolean enable)408   public void enableButton(@InCallButtonIds int buttonId, boolean enable) {
409     LogUtil.v(
410         "InCallFragment.enableButton",
411         "buttonId: %s, enable: %b",
412         InCallButtonIdsExtension.toString(buttonId),
413         enable);
414     if (isSupportedButton(buttonId)) {
415       getButtonController(buttonId).setEnabled(enable);
416     }
417   }
418 
419   @Override
setEnabled(boolean enabled)420   public void setEnabled(boolean enabled) {
421     LogUtil.v("InCallFragment.setEnabled", "enabled: " + enabled);
422     for (ButtonController buttonController : buttonControllers) {
423       buttonController.setEnabled(enabled);
424     }
425   }
426 
427   @Override
setHold(boolean value)428   public void setHold(boolean value) {
429     getButtonController(InCallButtonIds.BUTTON_HOLD).setChecked(value);
430   }
431 
432   @Override
setCameraSwitched(boolean isBackFacingCamera)433   public void setCameraSwitched(boolean isBackFacingCamera) {}
434 
435   @Override
setVideoPaused(boolean isPaused)436   public void setVideoPaused(boolean isPaused) {}
437 
438   @Override
setAudioState(CallAudioState audioState)439   public void setAudioState(CallAudioState audioState) {
440     LogUtil.i("InCallFragment.setAudioState", "audioState: " + audioState);
441     ((SpeakerButtonController) getButtonController(InCallButtonIds.BUTTON_AUDIO))
442         .setAudioState(audioState);
443     getButtonController(InCallButtonIds.BUTTON_MUTE).setChecked(audioState.isMuted());
444   }
445 
446   @Override
updateButtonStates()447   public void updateButtonStates() {
448     // When the incall screen is ready, this method is called from #setSecondary, even though the
449     // incall button ui is not ready yet. This method is called again once the incall button ui is
450     // ready though, so this operation is safe and will be executed asap.
451     if (inCallButtonGridFragment == null) {
452       return;
453     }
454     int numVisibleButtons =
455         inCallButtonGridFragment.updateButtonStates(
456             buttonControllers, buttonChooser, voiceNetworkType, phoneType);
457 
458     int visibility = numVisibleButtons == 0 ? View.GONE : View.VISIBLE;
459     pager.setVisibility(visibility);
460     if (adapter != null
461         && adapter.getCount() > 1
462         && getResources().getInteger(R.integer.incall_num_rows) > 1) {
463       paginator.setVisibility(View.VISIBLE);
464       pager.setSwipingLocked(false);
465     } else {
466       paginator.setVisibility(View.GONE);
467       if (adapter != null) {
468         pager.setSwipingLocked(true);
469         pager.setCurrentItem(adapter.getButtonGridPosition());
470       }
471     }
472   }
473 
474   @Override
updateInCallButtonUiColors(@olorInt int color)475   public void updateInCallButtonUiColors(@ColorInt int color) {
476     inCallButtonGridFragment.updateButtonColor(color);
477   }
478 
479   @Override
getInCallButtonUiFragment()480   public Fragment getInCallButtonUiFragment() {
481     return this;
482   }
483 
484   @Override
showAudioRouteSelector()485   public void showAudioRouteSelector() {
486     AudioRouteSelectorDialogFragment.newInstance(inCallButtonUiDelegate.getCurrentAudioState())
487         .show(getChildFragmentManager(), null);
488   }
489 
490   @Override
onAudioRouteSelected(int audioRoute)491   public void onAudioRouteSelected(int audioRoute) {
492     inCallButtonUiDelegate.setAudioRoute(audioRoute);
493   }
494 
495   @Override
onAudioRouteSelectorDismiss()496   public void onAudioRouteSelectorDismiss() {}
497 
498   @NonNull
499   @Override
getButtonController(@nCallButtonIds int id)500   public ButtonController getButtonController(@InCallButtonIds int id) {
501     for (ButtonController buttonController : buttonControllers) {
502       if (buttonController.getInCallButtonId() == id) {
503         return buttonController;
504       }
505     }
506     Assert.fail();
507     return null;
508   }
509 
510   @Override
onButtonGridCreated(InCallButtonGridFragment inCallButtonGridFragment)511   public void onButtonGridCreated(InCallButtonGridFragment inCallButtonGridFragment) {
512     LogUtil.i("InCallFragment.onButtonGridCreated", "InCallUiReady");
513     this.inCallButtonGridFragment = inCallButtonGridFragment;
514     inCallButtonUiDelegate.onInCallButtonUiReady(this);
515     updateButtonStates();
516   }
517 
518   @Override
onButtonGridDestroyed()519   public void onButtonGridDestroyed() {
520     LogUtil.i("InCallFragment.onButtonGridCreated", "InCallUiUnready");
521     inCallButtonUiDelegate.onInCallButtonUiUnready();
522     this.inCallButtonGridFragment = null;
523   }
524 
525   @Override
isShowingLocationUi()526   public boolean isShowingLocationUi() {
527     Fragment fragment = getLocationFragment();
528     return fragment != null && fragment.isVisible();
529   }
530 
531   @Override
showLocationUi(@ullable Fragment locationUi)532   public void showLocationUi(@Nullable Fragment locationUi) {
533     boolean isVisible = isShowingLocationUi();
534     if (locationUi != null && !isVisible) {
535       // Show the location fragment.
536       getChildFragmentManager()
537           .beginTransaction()
538           .replace(R.id.incall_location_holder, locationUi)
539           .commitAllowingStateLoss();
540     } else if (locationUi == null && isVisible) {
541       // Hide the location fragment
542       getChildFragmentManager()
543           .beginTransaction()
544           .remove(getLocationFragment())
545           .commitAllowingStateLoss();
546     }
547   }
548 
549   @Override
onMultiWindowModeChanged(boolean isInMultiWindowMode)550   public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
551     super.onMultiWindowModeChanged(isInMultiWindowMode);
552     if (isInMultiWindowMode == isShowingLocationUi()) {
553       LogUtil.i("InCallFragment.onMultiWindowModeChanged", "hide = " + isInMultiWindowMode);
554       // Need to show or hide location
555       showLocationUi(isInMultiWindowMode ? null : getLocationFragment());
556     }
557     contactGridManager.onMultiWindowModeChanged(isInMultiWindowMode);
558   }
559 
getLocationFragment()560   private Fragment getLocationFragment() {
561     return getChildFragmentManager().findFragmentById(R.id.incall_location_holder);
562   }
563 }
564