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.phone.testapps.imstestapp;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.os.Bundle;
22 import android.telephony.AccessNetworkConstants;
23 import android.telephony.SubscriptionManager;
24 import android.telephony.ims.ImsException;
25 import android.telephony.ims.ImsMmTelManager;
26 import android.telephony.ims.ImsReasonInfo;
27 import android.telephony.ims.RegistrationManager;
28 import android.telephony.ims.stub.ImsRegistrationImplBase;
29 import android.util.ArrayMap;
30 import android.util.Log;
31 import android.view.LayoutInflater;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.widget.AdapterView;
35 import android.widget.ArrayAdapter;
36 import android.widget.Button;
37 import android.widget.EditText;
38 import android.widget.ListView;
39 import android.widget.Spinner;
40 import android.widget.TextView;
41 import android.widget.Toast;
42 
43 import java.util.ArrayList;
44 import java.util.Map;
45 import java.util.Objects;
46 
47 public class ImsRegistrationActivity extends Activity {
48 
49     private static final String PREFIX_ITEM = "Registration Event: ";
50     private static final String PREFIX_VALUE = "Value: ";
51 
52 
53     private static class RegItem {
54         public String key;
55         public String value;
56 
RegItem(String key, int value)57         RegItem(String key, int value) {
58             this.key = key;
59             this.value = String.valueOf(value);
60         }
61 
RegItem(String key, String value)62         RegItem(String key, String value) {
63             this.key = key;
64             this.value = value;
65         }
66 
67         @Override
equals(Object o)68         public boolean equals(Object o) {
69             if (this == o) return true;
70             if (o == null || getClass() != o.getClass()) return false;
71             RegItem regItem = (RegItem) o;
72             return Objects.equals(key, regItem.key)
73                     && Objects.equals(value, regItem.value);
74         }
75 
76         @Override
hashCode()77         public int hashCode() {
78             return Objects.hash(key, value);
79         }
80     }
81 
82     private static class RegItemAdapter extends ArrayAdapter<RegItem> {
RegItemAdapter(Context context, ArrayList<RegItem> regItems)83         RegItemAdapter(Context context, ArrayList<RegItem> regItems) {
84             super(context, 0, regItems);
85         }
86 
87         @Override
getView(int position, View convertView, ViewGroup parent)88         public View getView(int position, View convertView, ViewGroup parent) {
89             RegItem regItem = getItem(position);
90 
91             if (convertView == null) {
92                 convertView = LayoutInflater.from(getContext()).inflate(R.layout.config_item,
93                         parent, false);
94             }
95 
96             TextView textItem = (TextView) convertView.findViewById(R.id.configItem);
97             TextView textValue = (TextView) convertView.findViewById(R.id.configValue);
98 
99             textItem.setText(PREFIX_ITEM + regItem.key);
100             textValue.setText(PREFIX_VALUE + regItem.value);
101 
102             return convertView;
103         }
104     }
105 
106 
107     private final RegistrationManager.RegistrationCallback mRegistrationCallback =
108             new RegistrationManager.RegistrationCallback() {
109 
110         @Override
111         public void onRegistered(int imsRadioTech) {
112             Log.i("ImsRegistrationActivity", "onRegistered: " + imsRadioTech);
113             mRegItems.add(new RegItem("Registered", REG_TECH_STRING.get(imsRadioTech)));
114             triggerAdapterChange();
115         }
116 
117         @Override
118         public void onRegistering(int imsRadioTech) {
119             Log.i("ImsRegistrationActivity", "onRegistering: " + imsRadioTech);
120             mRegItems.add(new RegItem("Registering", REG_TECH_STRING.get(imsRadioTech)));
121             triggerAdapterChange();
122         }
123 
124         @Override
125         public void onUnregistered(ImsReasonInfo info) {
126             Log.i("ImsRegistrationActivity", "onUnregistered: " + info);
127             mRegItems.add(new RegItem("Deregistered", info.toString()));
128             triggerAdapterChange();
129         }
130 
131         @Override
132         public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
133             mRegItems.add(new RegItem("TechnologyChangeFailed", REG_TECH_STRING.get(imsRadioTech)
134                     + " reason: " + info));
135             triggerAdapterChange();
136         }
137 
138         private void triggerAdapterChange() {
139             mRegItemAdapter.notifyDataSetChanged();
140         }
141     };
142 
143 
144 
145     private int mSelectedRegTech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
146 
147     private static final Map<String, Integer> REG_TECH = new ArrayMap<>(2);
148     static {
149         REG_TECH.put("LTE", ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
150         REG_TECH.put("IWLAN", ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
151     }
152     private static final Map<Integer, String> REG_TECH_STRING = new ArrayMap<>(2);
153     static {
REG_TECH_STRING.put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, "NONE")154         REG_TECH_STRING.put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, "NONE");
REG_TECH_STRING.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, "WWAN")155         REG_TECH_STRING.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, "WWAN");
REG_TECH_STRING.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, "WLAN")156         REG_TECH_STRING.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, "WLAN");
157     }
158 
159 
160 
161     private ArrayList<RegItem> mRegItems = new ArrayList<>();
162     RegItemAdapter mRegItemAdapter;
163     ListView mListView;
164 
165     private View mDeregisteredReason;
166     private View mRegChangeFailedReason;
167     private ImsMmTelManager mImsManager;
168 
169     @Override
onCreate(Bundle savedInstanceState)170     protected void onCreate(Bundle savedInstanceState) {
171         super.onCreate(savedInstanceState);
172 
173         setContentView(R.layout.activity_registration);
174     }
175 
176     @Override
onResume()177     protected void onResume() {
178         super.onResume();
179         mRegItemAdapter = new RegItemAdapter(this, mRegItems);
180         mListView = (ListView) findViewById(R.id.reg_cb_list);
181         mListView.setAdapter(mRegItemAdapter);
182         try {
183             mImsManager = ImsMmTelManager.createForSubscriptionId(
184                     SubscriptionManager.getDefaultVoiceSubscriptionId());
185             mImsManager.registerImsRegistrationCallback(getMainExecutor(), mRegistrationCallback);
186         } catch (IllegalArgumentException | ImsException e) {
187             Log.w("ImsCallingActivity", "illegal subscription ID.");
188         }
189 
190         //Set up registration tech spinner
191         Spinner regTechDropDown = findViewById(R.id.reg_tech_selector);
192         regTechDropDown.setAdapter(new ArrayAdapter<>(this,
193                 android.R.layout.simple_spinner_dropdown_item,
194                 REG_TECH.keySet().toArray(new String[REG_TECH.size()])));
195         regTechDropDown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
196 
197             @Override
198             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
199                 onTechDropDownChanged((String) parent.getItemAtPosition(position));
200             }
201 
202             @Override
203             public void onNothingSelected(AdapterView<?> parent) {
204                 // Don't change selection
205             }
206         });
207 
208         // Map buttons to onClick listeners
209         Button registeredButton = findViewById(R.id.reg_registered_button);
210         registeredButton.setOnClickListener((v)->onRegisteredClicked());
211         Button registeringButton = findViewById(R.id.reg_registering_button);
212         registeringButton.setOnClickListener((v)->onRegisteringClicked());
213         Button deregisteredButton = findViewById(R.id.reg_deregistered_button);
214         deregisteredButton.setOnClickListener((v)->onDeregisteredClicked());
215         Button regChangeFailedButton = findViewById(R.id.reg_changefailed_button);
216         regChangeFailedButton.setOnClickListener((v)->onRegChangeFailedClicked());
217 
218         mDeregisteredReason = findViewById(R.id.deregistered_imsreasoninfo);
219         mRegChangeFailedReason = findViewById(R.id.regchangefail_imsreasoninfo);
220     }
221 
222     @Override
onPause()223     protected void onPause() {
224         super.onPause();
225         mImsManager.unregisterImsRegistrationCallback(mRegistrationCallback);
226         mImsManager = null;
227     }
228 
onRegisteredClicked()229     private void onRegisteredClicked() {
230         if (!isFrameworkConnected()) {
231             return;
232         }
233         TestImsRegistrationImpl.getInstance().onRegistered(mSelectedRegTech);
234     }
235 
onRegisteringClicked()236     private void onRegisteringClicked() {
237         if (!isFrameworkConnected()) {
238             return;
239         }
240         TestImsRegistrationImpl.getInstance().onRegistering(mSelectedRegTech);
241     }
242 
onDeregisteredClicked()243     private void onDeregisteredClicked() {
244         if (!isFrameworkConnected()) {
245             return;
246         }
247         TestImsRegistrationImpl.getInstance().onDeregistered(getReasonInfo(mDeregisteredReason));
248     }
249 
onRegChangeFailedClicked()250     private void onRegChangeFailedClicked() {
251         if (!isFrameworkConnected()) {
252             return;
253         }
254         TestImsRegistrationImpl.getInstance().onTechnologyChangeFailed(mSelectedRegTech,
255                 getReasonInfo(mRegChangeFailedReason));
256     }
257 
onTechDropDownChanged(String item)258     private void onTechDropDownChanged(String item) {
259         mSelectedRegTech = REG_TECH.get(item);
260     }
261 
getReasonInfo(View reasonView)262     private ImsReasonInfo getReasonInfo(View reasonView) {
263         EditText errorCodeText = reasonView.findViewById(R.id.imsreasoninfo_error);
264         EditText extraCodeText = reasonView.findViewById(R.id.imsreasoninfo_extra);
265         EditText messageText = reasonView.findViewById(R.id.imsreasoninfo_message);
266 
267         int errorCode = ImsReasonInfo.CODE_UNSPECIFIED;
268         try {
269             errorCode = Integer.parseInt(errorCodeText.getText().toString());
270         } catch (NumberFormatException e) {
271             Toast.makeText(this, "Couldn't parse reason, defaulting to Unspecified.",
272                     Toast.LENGTH_SHORT).show();
273         }
274 
275         int extraCode = ImsReasonInfo.CODE_UNSPECIFIED;
276         try {
277             extraCode = Integer.parseInt(extraCodeText.getText().toString());
278         } catch (NumberFormatException e) {
279             Toast.makeText(this, "Couldn't parse reason, defaulting to Unspecified.",
280                     Toast.LENGTH_SHORT).show();
281         }
282 
283         String message = messageText.getText().toString();
284 
285         ImsReasonInfo result = new ImsReasonInfo(errorCode, extraCode, message);
286         Toast.makeText(this, "getReasonInfo: " + result, Toast.LENGTH_SHORT).show();
287         return result;
288     }
289 
isFrameworkConnected()290     private boolean isFrameworkConnected() {
291         if (TestImsRegistrationImpl.getInstance() == null) {
292             Toast.makeText(this, "Connection to Framework Unavailable!",
293                     Toast.LENGTH_LONG).show();
294             return false;
295         }
296         return true;
297     }
298 }
299