Home | History | Annotate | Download | only in incallui
      1 /*
      2  * Copyright (C) 2017 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;
     18 
     19 import android.app.PendingIntent;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.graphics.drawable.Icon;
     23 import android.support.annotation.NonNull;
     24 import android.support.annotation.VisibleForTesting;
     25 import android.telecom.CallAudioState;
     26 import com.android.dialer.common.LogUtil;
     27 import com.android.dialer.configprovider.ConfigProviderBindings;
     28 import com.android.dialer.telecom.TelecomUtil;
     29 import com.android.dialershared.bubble.Bubble;
     30 import com.android.dialershared.bubble.BubbleInfo;
     31 import com.android.dialershared.bubble.BubbleInfo.Action;
     32 import com.android.incallui.InCallPresenter.InCallUiListener;
     33 import com.android.incallui.audiomode.AudioModeProvider;
     34 import com.android.incallui.audiomode.AudioModeProvider.AudioModeListener;
     35 import com.android.incallui.call.CallList;
     36 import com.android.incallui.call.CallList.Listener;
     37 import com.android.incallui.call.DialerCall;
     38 import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo;
     39 import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo.IconSize;
     40 import java.util.ArrayList;
     41 import java.util.List;
     42 
     43 /**
     44  * Listens for events relevant to the return-to-call bubble and updates the bubble's state as
     45  * necessary
     46  */
     47 public class ReturnToCallController implements InCallUiListener, Listener, AudioModeListener {
     48 
     49   private final Context context;
     50 
     51   @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     52   Bubble bubble;
     53 
     54   private CallAudioState audioState;
     55 
     56   private final PendingIntent toggleSpeaker;
     57   private final PendingIntent showSpeakerSelect;
     58   private final PendingIntent toggleMute;
     59   private final PendingIntent endCall;
     60 
     61   public static boolean isEnabled(Context context) {
     62     return ConfigProviderBindings.get(context).getBoolean("enable_return_to_call_bubble", false);
     63   }
     64 
     65   public ReturnToCallController(Context context) {
     66     this.context = context;
     67 
     68     toggleSpeaker = createActionIntent(ReturnToCallActionReceiver.ACTION_TOGGLE_SPEAKER);
     69     showSpeakerSelect =
     70         createActionIntent(ReturnToCallActionReceiver.ACTION_SHOW_AUDIO_ROUTE_SELECTOR);
     71     toggleMute = createActionIntent(ReturnToCallActionReceiver.ACTION_TOGGLE_MUTE);
     72     endCall = createActionIntent(ReturnToCallActionReceiver.ACTION_END_CALL);
     73 
     74     InCallPresenter.getInstance().addInCallUiListener(this);
     75     CallList.getInstance().addListener(this);
     76     AudioModeProvider.getInstance().addListener(this);
     77     audioState = AudioModeProvider.getInstance().getAudioState();
     78   }
     79 
     80   public void tearDown() {
     81     InCallPresenter.getInstance().removeInCallUiListener(this);
     82     CallList.getInstance().removeListener(this);
     83     AudioModeProvider.getInstance().removeListener(this);
     84   }
     85 
     86   @Override
     87   public void onUiShowing(boolean showing) {
     88     if (showing) {
     89       hide();
     90     } else {
     91       if (TelecomUtil.isInCall(context)) {
     92         show();
     93       }
     94     }
     95   }
     96 
     97   private void hide() {
     98     if (bubble != null) {
     99       bubble.hide();
    100     } else {
    101       LogUtil.i("ReturnToCallController.hide", "hide() called without calling show()");
    102     }
    103   }
    104 
    105   private void show() {
    106     if (bubble == null) {
    107       bubble = startNewBubble();
    108     } else {
    109       bubble.show();
    110     }
    111   }
    112 
    113   private Bubble startNewBubble() {
    114     if (!Bubble.canShowBubbles(context)) {
    115       LogUtil.i("ReturnToCallController.startNewBubble", "can't show bubble, no permission");
    116       return null;
    117     }
    118     Bubble returnToCallBubble = Bubble.createBubble(context, generateBubbleInfo());
    119     returnToCallBubble.show();
    120     return returnToCallBubble;
    121   }
    122 
    123   @Override
    124   public void onIncomingCall(DialerCall call) {}
    125 
    126   @Override
    127   public void onUpgradeToVideo(DialerCall call) {}
    128 
    129   @Override
    130   public void onSessionModificationStateChange(DialerCall call) {}
    131 
    132   @Override
    133   public void onCallListChange(CallList callList) {}
    134 
    135   @Override
    136   public void onDisconnect(DialerCall call) {
    137     if (bubble != null && bubble.isVisible()) {
    138       bubble.showText(context.getText(R.string.incall_call_ended));
    139     }
    140 
    141     if (!TelecomUtil.isInCall(context)) {
    142       hide();
    143     }
    144   }
    145 
    146   @Override
    147   public void onWiFiToLteHandover(DialerCall call) {}
    148 
    149   @Override
    150   public void onHandoverToWifiFailed(DialerCall call) {}
    151 
    152   @Override
    153   public void onInternationalCallOnWifi(@NonNull DialerCall call) {}
    154 
    155   @Override
    156   public void onAudioStateChanged(CallAudioState audioState) {
    157     this.audioState = audioState;
    158     if (bubble != null) {
    159       bubble.updateActions(generateActions());
    160     }
    161   }
    162 
    163   private BubbleInfo generateBubbleInfo() {
    164     Intent activityIntent = InCallActivity.getIntent(context, false, false, false);
    165     activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    166     return BubbleInfo.builder()
    167         .setPrimaryColor(context.getResources().getColor(R.color.dialer_theme_color, null))
    168         .setPrimaryIcon(Icon.createWithResource(context, R.drawable.on_going_call))
    169         .setStartingYPosition(
    170             context.getResources().getDimensionPixelOffset(R.dimen.return_to_call_initial_offset_y))
    171         .setPrimaryIntent(PendingIntent.getActivity(context, 0, activityIntent, 0))
    172         .setActions(generateActions())
    173         .build();
    174   }
    175 
    176   @NonNull
    177   private List<Action> generateActions() {
    178     List<Action> actions = new ArrayList<>();
    179     SpeakerButtonInfo speakerButtonInfo = new SpeakerButtonInfo(audioState, IconSize.SIZE_24_DP);
    180 
    181     actions.add(
    182         Action.builder()
    183             .setIcon(Icon.createWithResource(context, speakerButtonInfo.icon))
    184             .setName(context.getText(speakerButtonInfo.label))
    185             .setChecked(speakerButtonInfo.isChecked)
    186             .setIntent(speakerButtonInfo.checkable ? toggleSpeaker : showSpeakerSelect)
    187             .build());
    188 
    189     actions.add(
    190         Action.builder()
    191             .setIcon(Icon.createWithResource(context, R.drawable.quantum_ic_mic_off_white_24))
    192             .setName(context.getText(R.string.incall_label_mute))
    193             .setChecked(audioState.isMuted())
    194             .setIntent(toggleMute)
    195             .build());
    196     actions.add(
    197         Action.builder()
    198             .setIcon(Icon.createWithResource(context, R.drawable.quantum_ic_call_end_white_24))
    199             .setName(context.getText(R.string.incall_label_end_call))
    200             .setIntent(endCall)
    201             .build());
    202     return actions;
    203   }
    204 
    205   @NonNull
    206   private PendingIntent createActionIntent(String action) {
    207     Intent toggleSpeaker = new Intent(context, ReturnToCallActionReceiver.class);
    208     toggleSpeaker.setAction(action);
    209     return PendingIntent.getBroadcast(context, 0, toggleSpeaker, 0);
    210   }
    211 }
    212