• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.services.telephony.domainselection;
18 
19 import android.annotation.NonNull;
20 import android.content.Context;
21 import android.os.Looper;
22 import android.os.Message;
23 import android.telephony.DisconnectCause;
24 import android.telephony.DomainSelectionService;
25 import android.telephony.DomainSelectionService.SelectionAttributes;
26 import android.telephony.NetworkRegistrationInfo;
27 import android.telephony.TransportSelectorCallback;
28 
29 /**
30  * Implements SMS domain selector for sending MO SMS.
31  */
32 public class SmsDomainSelector extends DomainSelectorBase implements
33         ImsStateTracker.ImsStateListener {
34     protected static final int EVENT_SELECT_DOMAIN = 101;
35 
36     protected boolean mDestroyed = false;
37     private boolean mDomainSelectionRequested = false;
38 
SmsDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener listener)39     public SmsDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper,
40             @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener listener) {
41         this(context, slotId, subId, looper, imsStateTracker, listener, "DomainSelector-SMS");
42     }
43 
SmsDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener listener, String logTag)44     protected SmsDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper,
45             @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener listener,
46             String logTag) {
47         super(context, slotId, subId, looper, imsStateTracker, listener, logTag);
48     }
49 
50     @Override
destroy()51     public void destroy() {
52         if (mDestroyed) {
53             return;
54         }
55         logd("destroy");
56         mDestroyed = true;
57         mImsStateTracker.removeImsStateListener(this);
58         super.destroy();
59     }
60 
61     @Override
handleMessage(@onNull Message msg)62     public void handleMessage(@NonNull Message msg) {
63         switch (msg.what) {
64             case EVENT_SELECT_DOMAIN:
65                 selectDomain();
66                 break;
67             default:
68                 super.handleMessage(msg);
69                 break;
70         }
71     }
72 
73     @Override
cancelSelection()74     public void cancelSelection() {
75         logi("cancelSelection");
76         finishSelection();
77     }
78 
79     @Override
reselectDomain(@onNull SelectionAttributes attr)80     public void reselectDomain(@NonNull SelectionAttributes attr) {
81         if (isDomainSelectionRequested()) {
82             // The domain selection is already requested,
83             // so we don't need to request it again before completing the previous task.
84             logi("Domain selection is already running.");
85             return;
86         }
87 
88         logi("reselectDomain");
89         mSelectionAttributes = attr;
90         setDomainSelectionRequested(true);
91         obtainMessage(EVENT_SELECT_DOMAIN).sendToTarget();
92     }
93 
94     @Override
finishSelection()95     public void finishSelection() {
96         logi("finishSelection");
97         setDomainSelectionRequested(false);
98         mSelectionAttributes = null;
99         mTransportSelectorCallback = null;
100         mWwanSelectorCallback = null;
101         destroy();
102     }
103 
104     @Override
selectDomain(SelectionAttributes attr, TransportSelectorCallback callback)105     public void selectDomain(SelectionAttributes attr, TransportSelectorCallback callback) {
106         if (isDomainSelectionRequested()) {
107             // The domain selection is already requested,
108             // so we don't need to request it again before completing the previous task.
109             logi("Domain selection is already running.");
110             return;
111         }
112         mSelectionAttributes = attr;
113         mTransportSelectorCallback = callback;
114         setDomainSelectionRequested(true);
115         mImsStateTracker.addImsStateListener(this);
116         obtainMessage(EVENT_SELECT_DOMAIN).sendToTarget();
117     }
118 
119     @Override
onImsMmTelFeatureAvailableChanged()120     public void onImsMmTelFeatureAvailableChanged() {
121         sendMessageForDomainSelection();
122     }
123 
124     @Override
onImsRegistrationStateChanged()125     public void onImsRegistrationStateChanged() {
126         sendMessageForDomainSelection();
127     }
128 
129     @Override
onImsMmTelCapabilitiesChanged()130     public void onImsMmTelCapabilitiesChanged() {
131         sendMessageForDomainSelection();
132     }
133 
isSmsOverImsAvailable()134     protected boolean isSmsOverImsAvailable() {
135         return mImsStateTracker.isImsSmsCapable()
136                 && mImsStateTracker.isImsRegistered()
137                 && mImsStateTracker.isMmTelFeatureAvailable();
138     }
139 
selectDomain()140     protected void selectDomain() {
141         if (!isDomainSelectionRequested()) {
142             logi("Domain selection is not requested!");
143             return;
144         }
145 
146         logi("selectDomain: " + mImsStateTracker.imsStateToString());
147 
148         if (isSmsOverImsAvailable()) {
149             if (mImsStateTracker.isImsRegisteredOverWlan()) {
150                 notifyWlanSelected(false);
151                 return;
152             }
153             notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_PS, false);
154         } else {
155             notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_CS, false);
156         }
157     }
158 
sendMessageForDomainSelection()159     protected void sendMessageForDomainSelection() {
160         // If the event is already queued to this handler,
161         // it will be removed first to avoid the duplicate operation.
162         removeMessages(EVENT_SELECT_DOMAIN);
163         // Since the IMS state may have already been posted,
164         // proceed with the domain selection after processing all pending messages.
165         obtainMessage(EVENT_SELECT_DOMAIN).sendToTarget();
166     }
167 
isDomainSelectionRequested()168     protected boolean isDomainSelectionRequested() {
169         return mDomainSelectionRequested;
170     }
171 
setDomainSelectionRequested(boolean requested)172     protected void setDomainSelectionRequested(boolean requested) {
173         if (mDomainSelectionRequested != requested) {
174             logd("DomainSelectionRequested: " + mDomainSelectionRequested + " >> " + requested);
175             mDomainSelectionRequested = requested;
176         }
177     }
178 
notifyWlanSelected(boolean useEmergencyPdn)179     protected void notifyWlanSelected(boolean useEmergencyPdn) {
180         logi("DomainSelected: WLAN, E-PDN=" + useEmergencyPdn);
181         mTransportSelectorCallback.onWlanSelected(useEmergencyPdn);
182         setDomainSelectionRequested(false);
183     }
184 
notifyWwanSelected(@etworkRegistrationInfo.Domain int domain, boolean useEmergencyPdn)185     protected void notifyWwanSelected(@NetworkRegistrationInfo.Domain int domain,
186             boolean useEmergencyPdn) {
187         if (mWwanSelectorCallback == null) {
188             mTransportSelectorCallback.onWwanSelected((callback) -> {
189                 mWwanSelectorCallback = callback;
190                 notifyWwanSelectedInternal(domain, useEmergencyPdn);
191             });
192         } else {
193             notifyWwanSelectedInternal(domain, useEmergencyPdn);
194         }
195 
196         setDomainSelectionRequested(false);
197     }
198 
notifyWwanSelectedInternal(@etworkRegistrationInfo.Domain int domain, boolean useEmergencyPdn)199     protected void notifyWwanSelectedInternal(@NetworkRegistrationInfo.Domain int domain,
200             boolean useEmergencyPdn) {
201         logi("DomainSelected: WWAN/" + DomainSelectionService.getDomainName(domain)
202                 + ", E-PDN=" + useEmergencyPdn);
203 
204         if (mWwanSelectorCallback != null) {
205             mWwanSelectorCallback.onDomainSelected(domain, useEmergencyPdn);
206         } else {
207             mTransportSelectorCallback.onSelectionTerminated(DisconnectCause.LOCAL);
208         }
209     }
210 }
211