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.dialer.shortcuts; 18 19 import android.content.pm.PackageManager; 20 import android.net.Uri; 21 import android.os.Bundle; 22 import android.support.v4.app.ActivityCompat; 23 import android.widget.Toast; 24 import com.android.dialer.callintent.CallInitiationType; 25 import com.android.dialer.callintent.CallSpecificAppData; 26 import com.android.dialer.common.LogUtil; 27 import com.android.dialer.interactions.PhoneNumberInteraction; 28 import com.android.dialer.interactions.PhoneNumberInteraction.InteractionErrorCode; 29 import com.android.dialer.util.TransactionSafeActivity; 30 31 /** 32 * Invisible activity launched when a shortcut is selected by user. Calls a contact based on URI. 33 */ 34 public class CallContactActivity extends TransactionSafeActivity 35 implements PhoneNumberInteraction.DisambigDialogDismissedListener, 36 PhoneNumberInteraction.InteractionErrorListener, 37 ActivityCompat.OnRequestPermissionsResultCallback { 38 39 private static final String CONTACT_URI_KEY = "uri_key"; 40 41 private Uri contactUri; 42 43 @Override onCreate(Bundle savedInstanceState)44 public void onCreate(Bundle savedInstanceState) { 45 super.onCreate(savedInstanceState); 46 47 if ("com.android.dialer.shortcuts.CALL_CONTACT".equals(getIntent().getAction())) { 48 if (Shortcuts.areDynamicShortcutsEnabled(this)) { 49 LogUtil.i("CallContactActivity.onCreate", "shortcut clicked"); 50 contactUri = getIntent().getData(); 51 makeCall(); 52 } else { 53 LogUtil.i("CallContactActivity.onCreate", "dynamic shortcuts disabled"); 54 finish(); 55 } 56 } 57 } 58 59 @Override onDestroy()60 protected void onDestroy() { 61 super.onDestroy(); 62 LogUtil.enterBlock("CallContactActivity.onDestroy"); 63 } 64 65 /** 66 * Attempt to make a call, finishing the activity if the required permissions are already granted. 67 * If the required permissions are not already granted, the activity is not finished so that the 68 * user can choose to grant or deny them. 69 */ makeCall()70 private void makeCall() { 71 CallSpecificAppData callSpecificAppData = 72 CallSpecificAppData.newBuilder() 73 .setAllowAssistedDialing(true) 74 .setCallInitiationType(CallInitiationType.Type.LAUNCHER_SHORTCUT) 75 .build(); 76 PhoneNumberInteraction.startInteractionForPhoneCall( 77 this, contactUri, false /* isVideoCall */, callSpecificAppData); 78 } 79 80 @Override onDisambigDialogDismissed()81 public void onDisambigDialogDismissed() { 82 finish(); 83 } 84 85 @Override interactionError(@nteractionErrorCode int interactionErrorCode)86 public void interactionError(@InteractionErrorCode int interactionErrorCode) { 87 // Note: There is some subtlety to how contact lookup keys work that make it difficult to 88 // distinguish the case of the contact missing from the case of the a contact not having a 89 // number. For example, if a contact's phone number is deleted, subsequent lookups based on 90 // lookup key will actually return no results because the phone number was part of the 91 // lookup key. In this case, it would be inaccurate to say the contact can't be found though, so 92 // in all cases we just say the contact can't be found or the contact doesn't have a number. 93 switch (interactionErrorCode) { 94 case InteractionErrorCode.CONTACT_NOT_FOUND: 95 case InteractionErrorCode.CONTACT_HAS_NO_NUMBER: 96 Toast.makeText( 97 this, 98 R.string.dialer_shortcut_contact_not_found_or_has_no_number, 99 Toast.LENGTH_SHORT) 100 .show(); 101 break; 102 case InteractionErrorCode.USER_LEAVING_ACTIVITY: 103 case InteractionErrorCode.OTHER_ERROR: 104 default: 105 // If the user is leaving the activity or the error code was "other" there's no useful 106 // information to display but we still need to finish this invisible activity. 107 break; 108 } 109 finish(); 110 } 111 112 @Override onSaveInstanceState(Bundle outState)113 public void onSaveInstanceState(Bundle outState) { 114 super.onSaveInstanceState(outState); 115 outState.putParcelable(CONTACT_URI_KEY, contactUri); 116 } 117 118 @Override onRestoreInstanceState(Bundle savedInstanceState)119 public void onRestoreInstanceState(Bundle savedInstanceState) { 120 super.onRestoreInstanceState(savedInstanceState); 121 if (savedInstanceState == null) { 122 return; 123 } 124 contactUri = savedInstanceState.getParcelable(CONTACT_URI_KEY); 125 } 126 127 @Override onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults)128 public void onRequestPermissionsResult( 129 int requestCode, String[] permissions, int[] grantResults) { 130 switch (requestCode) { 131 case PhoneNumberInteraction.REQUEST_READ_CONTACTS: 132 case PhoneNumberInteraction.REQUEST_CALL_PHONE: 133 { 134 // If request is cancelled, the result arrays are empty. 135 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 136 makeCall(); 137 } else { 138 Toast.makeText(this, R.string.dialer_shortcut_no_permissions, Toast.LENGTH_SHORT) 139 .show(); 140 finish(); 141 } 142 break; 143 } 144 default: 145 throw new IllegalStateException("Unsupported request code: " + requestCode); 146 } 147 } 148 } 149