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             .setCallInitiationType(CallInitiationType.Type.LAUNCHER_SHORTCUT)
74             .build();
75     PhoneNumberInteraction.startInteractionForPhoneCall(
76         this, contactUri, false /* isVideoCall */, callSpecificAppData);
77   }
78 
79   @Override
onDisambigDialogDismissed()80   public void onDisambigDialogDismissed() {
81     finish();
82   }
83 
84   @Override
interactionError(@nteractionErrorCode int interactionErrorCode)85   public void interactionError(@InteractionErrorCode int interactionErrorCode) {
86     // Note: There is some subtlety to how contact lookup keys work that make it difficult to
87     // distinguish the case of the contact missing from the case of the a contact not having a
88     // number. For example, if a contact's phone number is deleted, subsequent lookups based on
89     // lookup key will actually return no results because the phone number was part of the
90     // lookup key. In this case, it would be inaccurate to say the contact can't be found though, so
91     // in all cases we just say the contact can't be found or the contact doesn't have a number.
92     switch (interactionErrorCode) {
93       case InteractionErrorCode.CONTACT_NOT_FOUND:
94       case InteractionErrorCode.CONTACT_HAS_NO_NUMBER:
95         Toast.makeText(
96                 this,
97                 R.string.dialer_shortcut_contact_not_found_or_has_no_number,
98                 Toast.LENGTH_SHORT)
99             .show();
100         break;
101       case InteractionErrorCode.USER_LEAVING_ACTIVITY:
102       case InteractionErrorCode.OTHER_ERROR:
103       default:
104         // If the user is leaving the activity or the error code was "other" there's no useful
105         // information to display but we still need to finish this invisible activity.
106         break;
107     }
108     finish();
109   }
110 
111   @Override
onSaveInstanceState(Bundle outState)112   public void onSaveInstanceState(Bundle outState) {
113     super.onSaveInstanceState(outState);
114     outState.putParcelable(CONTACT_URI_KEY, contactUri);
115   }
116 
117   @Override
onRestoreInstanceState(Bundle savedInstanceState)118   public void onRestoreInstanceState(Bundle savedInstanceState) {
119     super.onRestoreInstanceState(savedInstanceState);
120     if (savedInstanceState == null) {
121       return;
122     }
123     contactUri = savedInstanceState.getParcelable(CONTACT_URI_KEY);
124   }
125 
126   @Override
onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults)127   public void onRequestPermissionsResult(
128       int requestCode, String[] permissions, int[] grantResults) {
129     switch (requestCode) {
130       case PhoneNumberInteraction.REQUEST_READ_CONTACTS:
131       case PhoneNumberInteraction.REQUEST_CALL_PHONE:
132         {
133           // If request is cancelled, the result arrays are empty.
134           if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
135             makeCall();
136           } else {
137             Toast.makeText(this, R.string.dialer_shortcut_no_permissions, Toast.LENGTH_SHORT)
138                 .show();
139             finish();
140           }
141           break;
142         }
143       default:
144         throw new IllegalStateException("Unsupported request code: " + requestCode);
145     }
146   }
147 }
148