1 /*
2  * Copyright (C) 2018 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.car.settings.system;
18 
19 import android.app.ActivityManager;
20 import android.bluetooth.BluetoothAdapter;
21 import android.bluetooth.BluetoothManager;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.net.ConnectivityManager;
26 import android.net.NetworkPolicyManager;
27 import android.net.Uri;
28 import android.net.wifi.WifiManager;
29 import android.os.AsyncTask;
30 import android.os.Bundle;
31 import android.os.RecoverySystem;
32 import android.provider.Telephony;
33 import android.telephony.SubscriptionManager;
34 import android.telephony.TelephonyManager;
35 import android.text.TextUtils;
36 import android.widget.Toast;
37 
38 import androidx.annotation.VisibleForTesting;
39 import androidx.annotation.XmlRes;
40 import androidx.fragment.app.Fragment;
41 import androidx.preference.PreferenceManager;
42 
43 import com.android.car.settings.R;
44 import com.android.car.settings.common.ErrorDialog;
45 import com.android.car.settings.common.SettingsFragment;
46 import com.android.car.ui.toolbar.MenuItem;
47 
48 import java.util.Collections;
49 import java.util.List;
50 
51 /**
52  * Final warning presented to user to confirm restoring network settings to the factory default.
53  * If a user confirms, all settings are reset for connectivity, Wi-Fi, and Bluetooth.
54  */
55 public class ResetNetworkConfirmFragment extends SettingsFragment {
56 
57     // Copied from com.android.settings.network.ApnSettings.
58     @VisibleForTesting
59     static final String RESTORE_CARRIERS_URI = "content://telephony/carriers/restore";
60 
61     private MenuItem mResetButton;
62 
63     @Override
64     @XmlRes
getPreferenceScreenResId()65     protected int getPreferenceScreenResId() {
66         return R.xml.reset_network_confirm_fragment;
67     }
68 
69     @Override
getToolbarMenuItems()70     public List<MenuItem> getToolbarMenuItems() {
71         return Collections.singletonList(mResetButton);
72     }
73 
74     @Override
onCreate(Bundle savedInstanceState)75     public void onCreate(Bundle savedInstanceState) {
76         super.onCreate(savedInstanceState);
77 
78         mResetButton = new MenuItem.Builder(getContext())
79                 .setTitle(R.string.reset_network_confirm_button_text)
80                 .setOnClickListener(i -> resetNetwork())
81                 .build();
82     }
83 
resetNetwork()84     private void resetNetwork() {
85         if (ActivityManager.isUserAMonkey()) {
86             return;
87         }
88 
89         Context context = requireActivity().getApplicationContext();
90 
91         ConnectivityManager connectivityManager = (ConnectivityManager)
92                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
93         if (connectivityManager != null) {
94             connectivityManager.factoryReset();
95         }
96 
97         WifiManager wifiManager = (WifiManager)
98                 context.getSystemService(Context.WIFI_SERVICE);
99         if (wifiManager != null) {
100             wifiManager.factoryReset();
101         }
102 
103         BluetoothManager btManager = (BluetoothManager)
104                 context.getSystemService(Context.BLUETOOTH_SERVICE);
105         if (btManager != null) {
106             BluetoothAdapter btAdapter = btManager.getAdapter();
107             if (btAdapter != null) {
108                 btAdapter.factoryReset();
109             }
110         }
111 
112         int networkSubscriptionId = getNetworkSubscriptionId();
113         TelephonyManager telephonyManager = (TelephonyManager)
114                 context.getSystemService(Context.TELEPHONY_SERVICE);
115         if (telephonyManager != null) {
116             telephonyManager.factoryReset(networkSubscriptionId);
117         }
118 
119         NetworkPolicyManager policyManager = (NetworkPolicyManager)
120                 context.getSystemService(Context.NETWORK_POLICY_SERVICE);
121         if (policyManager != null) {
122             String subscriberId = telephonyManager.getSubscriberId(networkSubscriptionId);
123             policyManager.factoryReset(subscriberId);
124         }
125 
126         restoreDefaultApn(context, networkSubscriptionId);
127 
128         // There has been issues when Sms raw table somehow stores orphan
129         // fragments. They lead to garbled message when new fragments come
130         // in and combined with those stale ones. In case this happens again,
131         // user can reset all network settings which will clean up this table.
132         cleanUpSmsRawTable(context);
133 
134         if (shouldResetEsim()) {
135             new EraseEsimAsyncTask(getContext(), context.getPackageName(), this).execute();
136         } else {
137             showCompletionToast(getContext());
138         }
139     }
140 
shouldResetEsim()141     private boolean shouldResetEsim() {
142         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
143                 requireContext());
144         return sharedPreferences.getBoolean(requireContext().getString(R.string.pk_reset_esim),
145                 false);
146     }
147 
getNetworkSubscriptionId()148     private int getNetworkSubscriptionId() {
149         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(
150                 requireContext());
151         String stringId = sharedPreferences.getString(
152                 requireContext().getString(R.string.pk_reset_network_subscription), null);
153         if (TextUtils.isEmpty(stringId)) {
154             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
155         }
156         return Integer.parseInt(stringId);
157     }
158 
restoreDefaultApn(Context context, int subscriptionId)159     private void restoreDefaultApn(Context context, int subscriptionId) {
160         Uri uri = Uri.parse(RESTORE_CARRIERS_URI);
161 
162         if (SubscriptionManager.isUsableSubIdValue(subscriptionId)) {
163             uri = Uri.withAppendedPath(uri, "subId/" + subscriptionId);
164         }
165 
166         ContentResolver resolver = context.getContentResolver();
167         resolver.delete(uri, null, null);
168     }
169 
cleanUpSmsRawTable(Context context)170     private void cleanUpSmsRawTable(Context context) {
171         ContentResolver resolver = context.getContentResolver();
172         Uri uri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
173         resolver.delete(uri, null, null);
174     }
175 
showCompletionToast(Context context)176     private static void showCompletionToast(Context context) {
177         Toast.makeText(context, R.string.reset_network_complete_toast,
178                 Toast.LENGTH_SHORT).show();
179     }
180 
181     private static class EraseEsimAsyncTask extends AsyncTask<Void, Void, Boolean> {
182 
183         private final Context mContext;
184         private final String mPackageName;
185         private final Fragment mFragment;
186 
EraseEsimAsyncTask(Context context, String packageName, Fragment parent)187         EraseEsimAsyncTask(Context context, String packageName, Fragment parent) {
188             mContext = context;
189             mPackageName = packageName;
190             mFragment = parent;
191         }
192 
193         @Override
doInBackground(Void... voids)194         protected Boolean doInBackground(Void... voids) {
195             return RecoverySystem.wipeEuiccData(mContext, mPackageName);
196         }
197 
198         @Override
onPostExecute(Boolean succeeded)199         protected void onPostExecute(Boolean succeeded) {
200             if (succeeded) {
201                 showCompletionToast(mContext);
202             } else {
203                 ErrorDialog.show(mFragment, R.string.reset_esim_error_title);
204             }
205         }
206     }
207 }
208